Retrieving a List from a java.util.stream.Stream in Java 8

I was playing around with Java 8 lambdas to easily filter collections. But I did not find a concise way to retrieve the result as a new list within the same statement. Here is my most concise approach so far:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);

Examples on the net did not answer my question because they stop without generating a new result list. There must be a more concise way. I would have expected, that the Stream class has methods as toList(), toSet(), …

Is there a way that the variables targetLongList can be directly be assigned by the third line?


What you are doing may be the simplest way, provided your stream stays sequential—otherwise you will have to put a call to sequential() before forEach.

[later edit: the reason the call to sequential() is necessary is that the code as it stands (forEach(targetLongList::add)) would be racy if the stream was parallel. Even then, it will not achieve the effect intended, as forEach is explicitly nondeterministic—even in a sequential stream the order of element processing is not guaranteed. You would have to use forEachOrdered to ensure correct ordering. The intention of the Stream API designers is that you will use collector in this situation, as below.]

An alternative is

targetLongList = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(Collectors.toList());

Updated:

Another approach is to use Collectors.toList:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toList());

Previous Solution:

Another approach is to use Collectors.toCollection:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toCollection(ArrayList::new));

I like to use a util method that returns a collector for ArrayList when that is what I want.

I think the solution using Collectors.toCollection(ArrayList::new) is a little too noisy for such a common operation.

Example:

ArrayList<Long> result = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(toArrayList());

public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
    return Collectors.toCollection(ArrayList::new);
}

With this answer I also want to demonstrate how simple it is to create and use custom collectors, which is very useful generally.


collect(Collectors.toList());

This is the call which you can use to convert any Stream to List.

more concretely:

    List<String> myList = stream.collect(Collectors.toList()); 

from:

https://www.geeksforgeeks.org/collectors-tolist-method-in-java-with-examples/


If you have an array of primitives, you can use the primitive collections available in Eclipse Collections.

LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);

If you can't change the sourceLongList from List:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = 
    ListAdapter.adapt(sourceLongList).select(l -> l > 100, new ArrayList<>());

If you want to use LongStream:

long[] sourceLongs = new long[]{1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L};
LongList targetList = 
    LongStream.of(sourceLongs)
    .filter(l -> l > 100)
    .collect(LongArrayList::new, LongArrayList::add, LongArrayList::addAll);

Note: I am a contributor to Eclipse Collections.