12

By writing applications in Java there are many use cases for java.util.Collection. Since java.util.stream.Stream was introduced with Java 8, I came over some use-cases where it is difficult to decide what to use.

For example: You are going to write some util-methods.

public static List<?> filterHashToList(int hash, Collection<?> toFilter) {
    return toFilter.stream()
        .filter((Object o) -> hash == o.hashCode())
        .collect(Collectors.toCollection(LinkedList::new));
}

What about writing it like this:

public static List<?> filterHashToList(int hash, Collection<?> toFilter) {
    List<Object> result = new LinkedList<>();

    for(Object o : toFilter) {
        if(hash == o.hashCode()) {
            result.add(o);
        }
    }

    return result;
}

Both methods would produce the same result. java.util.stream.Stream and java.util.stream.Collector are interfaces, so the implementation can vary as well if I use custom streams and collectors.

I think there are loads of implementations out there using the old-fashoined loop-way.

So, is it possible to answer what to use, stream or loop, by use-case? And if so, do all implementations have to be updated where appropriate?

Or should I even provide both ways by implementing util-methods? Or should I also provide a mthed returning the stream after the filtering process so you can work with that one too if required?

10
  • 3
    I would use two simple rules: 1. if it ain't broken, don't fix it. 2. use what you find the most readable and maintainable. That said, your two examples don't return the same thing: one returns an ArrayList, and the other one returns a LinkedList.
    – JB Nizet
    Commented Sep 19, 2015 at 16:19
  • 8
    There's nothing magic about either streams or loops. You should write the code that is most readable, clear, and maintainable. Either of these are acceptable. (Note that you might want to use toCollection(LinkedList::New) in the first example if a LinkedList is really what you want.) Commented Sep 19, 2015 at 16:19
  • 2
    @JBNizet Agree, except you can't count on toList() returning an ArrayList. It returns a List -- that's all you know. Commented Sep 19, 2015 at 16:20
  • 3
    @BrianGoetz agreed. Please tell me you don't actually plan to return a LinkedList in the future :-)
    – JB Nizet
    Commented Sep 19, 2015 at 16:20
  • 1
    @JBNizet said it all: if it works, don't fix it. However, out of curiosity, why a LinkedList at all? Since you return a List, you don't have any access to any methods specific to LinkedList anyway, and ArrayList performs better as a whole...
    – fge
    Commented Sep 19, 2015 at 17:06

3 Answers 3

9

In the absence of a posted answer I will quote Brian Goetz who echoes my sentiment and I suspect many others'.

There's nothing magic about either streams or loops. You should write the code that is most readable, clear, and maintainable. Either of these are acceptable.

5

Note that in your implementation you stick with specific resulting collection type LinkedList which usually has very poor performance compared to ArrayList. What if the user of your method wants to use the resulting list in random-access manner? Probably the user of this method needs an array, because it should be passed to another API method which accepts an array. Sometimes the user just need to know how many objects with given hashCode are present in the input collection, thus there's no need to create a resulting list at all. The Java-8 way is to return streams from the methods, not the collections and let the caller decide how to collect it:

public static <T> Stream<T> filterHashToList(int hash, Collection<T> toFilter) {
    return toFilter.stream()
        .filter(o -> hash == o.hashCode());
}

And use it:

filterHashToList(42, input).count();

Or

filterHashToList(42, input).collect(toCollection(ArrayList::new));

Or

filterHashToList(42, input).toArray();

This way the method becomes very simple, so you probably don't need it at all, but if you want to do more sofisticated filtering/transformation, it's ok.

So if you don't want to change the API and still return the LinkedList, there's no need to change the implementation. But if you want to take the advantage from using Stream API, it's better to change the return type to Stream.

0

I think this is largely dependent on the anticipated size of the Collection and practical application of the program. The former is slightly more efficient, but I find it less readable and there are still systems that run on Java 7 (ie Google App Engine). Additionally, the latter would likely be easier to add more complex filters to going forward. However, if efficiency is the primary concern, I would go with the former.

Not the answer you're looking for? Browse other questions tagged or ask your own question.