views:

107

answers:

4

I'm trying to write my own "functional" little lib in Java. If I have this function :

public static <T> List<T> filter(Iterable<T> source,BooleanTest predicate)
{
    List<T> results = new ArrayList<T>();
    for(T t : source)
    {
         if(predicate.ok(t))
            results.add(t);
    }
    return results;
}

why can't I use it with this snippet:

String strings[] = {"one","two","three"};
List<String> containingO = IterableFuncs.filter(strings,new BooleanTest() {
   public boolean ok(String obj) {
     return obj.indexOf("o") != -1;
   }
});

As far as I know, a Java array implements Iterable, right? What needs to be changed to make the function work with arrays, as well as collections? By choosing Iterable as the first parameter, I figured I got all cases covered.

+11  A: 

Arrays don't implement any interfaces in Java, unfortunately. The enhanced for loop works over arrays and iterables, separately.

However, you can use Arrays.asList(T...) to wrap an array in a List<T> which is iterable.

In terms of the "functional library" side of things, you should probably have a look at Google Collections which has a lot of similar stuff in.

Jon Skeet
So, I'd need to implement two versions? One taking an `Iterable`, and one taking variable length arguments?
Geo
Or start with a `Collection` in the first place.
Tom Hawtin - tackline
Yeah, but it would be nice to be able to use arrays as well.
Geo
Geo, the excellent book *Java Generics and Collections* basically suggests treating arrays as a deprecated type. For my own API, I would always favor avoiding arrays.
Fabian Steeg
I wouldn't go as far as to treat arrays as deprecated - although I would *usually* avoid exposing them. The fact that they can handle primitives efficiently is a definite point in their favour...
Jon Skeet
And yes Enum.values() (added in Java 5) bizarrely returns an array. Go figure.
cletus
@cletus: That's particularly annoying, as it means it can't be an immutable singleton... pointless (though small) performance hit every time it's called :(
Jon Skeet
+2  A: 

Java arrays are not Iterable even though the enhanced for loop can iterate over them.

The usual way I handle this is:

public void doStuff(String... args) {
  doStuff(Arrays.asList(args));
}

and either:

public void doStuff(Iterable<String> args) {
  ...
}

or:

public void doStuff(Collection<String> args) {
  ...
}
cletus
A: 

arrays are designed to be lightweight. they do not implement iterable.

unfortunately you'll need to overload ie write another version of the same method for the array type or convert it to a collection (which would be less efficient).

pstanton
+1  A: 

I agree, it's annoying.

You could overload filter() thusly...

public static <T> List<T> filter(T[] source, BooleanTest predicate)
{
    return filter(Arrays.asList(source), predicate);
}
Drew Wills
A little offtopic, but why would `public static <T> ArrayList<T> filter(T... args,BooleanTest predicate)` give a missing `)` error?
Geo
Because a varargs parameter, if present, must be the last parameter in a method signature. The compiler is complaining that it doesn't see ')' after 'T... args'
Drew Wills