[java] 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?

This question is related to java lambda collections java-8 java-stream

The answer is


To collect in a mutable list:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toList());

To collect in a immutable list:

targetList = sourceList.stream()
                       .filter(i -> i > 100) //apply filter
                       .collect(Collectors.toUnmodifiableList());

Explanation of collect from the JavaDoc:

Performs a mutable reduction operation on the elements of this stream using a Collector. A Collector encapsulates the functions used as arguments to collect(Supplier, BiConsumer, BiConsumer), allowing for reuse of collection strategies and composition of collect operations such as multiple-level grouping or partitioning. If the stream is parallel, and the Collector is concurrent, and either the stream is unordered or the collector is unordered, then a concurrent reduction will be performed (see Collector for details on concurrent reduction.)

This is a terminal operation.

When executed in parallel, multiple intermediate results may be instantiated, populated, and merged so as to maintain isolation of mutable data structures. Therefore, even when executed in parallel with non-thread-safe data structures (such as ArrayList), no additional synchronization is needed for a parallel reduction.


Here is code by AbacusUtil

LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();

Disclosure: I'm the developer of AbacusUtil.


String joined = 
                Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
                      .filter(s -> s != null && !s.isEmpty())
                      .collect(Collectors.joining(","));

There is an another variant of collect method provided by LongStream class and similarly by IntStream and DoubleStream classes too .

<R> R collect(Supplier<R> supplier,
              ObjLongConsumer<R> accumulator,
              BiConsumer<R,R> combiner)

Performs a mutable reduction operation on the elements of this stream. A mutable reduction is one in which the reduced value is a mutable result container, such as an ArrayList, and elements are incorporated by updating the state of the result rather than by replacing the result. This produces a result equivalent to:

R result = supplier.get();
  for (long element : this stream)
       accumulator.accept(result, element);
  return result;

Like reduce(long, LongBinaryOperator), collect operations can be parallelized without requiring additional synchronization. This is a terminal operation.

And answer to your question with this collect method is as below :

    LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, (list, value) -> list.add(value)
    , (list1, list2) -> list1.addAll(list2));

Below is the method reference variant which is quite smart but some what tricky to understand :

     LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, List::add , List::addAll);

Below will be the HashSet variant :

     LongStream.of(1L, 2L, 3L, 3).filter(i -> i > 2)
     .collect(HashSet::new, HashSet::add, HashSet::addAll);

Similarly LinkedList variant is like this :

     LongStream.of(1L, 2L, 3L, 3L)
     .filter(i -> i > 2)
     .collect(LinkedList::new, LinkedList::add, LinkedList::addAll);

If you don't mind using 3rd party libraries, AOL's cyclops-react lib (disclosure I am a contributor) has extensions for all JDK Collection types, including List. The ListX interface extends java.util.List and adds a large number of useful operators, including filter.

You can simply write-

ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);

ListX also can be created from an existing List (via ListX.fromIterable)


A little more efficient way (avoid the creating the source List and the auto-unboxing by the filter):

List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
    .filter(l -> l > 100)
    .boxed()
    .collect(Collectors.toList());

If you don't use parallel() this will work

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);

List<Long> targetLongList =  new ArrayList<Long>();

sourceLongList.stream().peek(i->targetLongList.add(i)).collect(Collectors.toList());

There is a new method Stream.toList() in Java 16:

List<Long> targetLongList = sourceLongList
         .stream()
         .filter(l -> l > 100)
         .toList();

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/


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));

In case someone (like me) out there is looking for ways deal with Objects instead of primitive types then use mapToObj()

String ss = "An alternative way is to insert the following VM option before "
        + "the -vmargs option in the Eclipse shortcut properties(edit the "
        + "field Target inside the Shortcut tab):";

List<Character> ll = ss
                        .chars()
                        .mapToObj(c -> new Character((char) c))
                        .collect(Collectors.toList());

System.out.println("List type: " + ll.getClass());
System.out.println("Elem type: " + ll.get(0).getClass());
ll.stream().limit(50).forEach(System.out::print);

prints:

List type: class java.util.ArrayList
Elem type: class java.lang.Character
An alternative way is to insert the following VM o

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.


You can rewrite code as below :

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = sourceLongList.stream().filter(l -> l > 100).collect(Collectors.toList());

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.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to lambda

Java 8 optional: ifPresent return object orElseThrow exception How to properly apply a lambda function into a pandas data frame column What are functional interfaces used for in Java 8? Java 8 lambda get and remove element from list Variable used in lambda expression should be final or effectively final Filter values only if not null using lambda in Java8 forEach loop Java 8 for Map entry set Java 8 Lambda Stream forEach with multiple statements Java 8 stream map to list of keys sorted by values Task.Run with Parameter(s)?

Examples related to collections

Kotlin's List missing "add", "remove", Map missing "put", etc? How to unset (remove) a collection element after fetching it? How can I get a List from some class properties with Java 8 Stream? Java 8 stream map to list of keys sorted by values How to convert String into Hashmap in java How can I turn a List of Lists into a List in Java 8? MongoDB Show all contents from all collections Get nth character of a string in Swift programming language Java 8 Distinct by property Is there a typescript List<> and/or Map<> class/library?

Examples related to java-8

Default interface methods are only supported starting with Android N Class has been compiled by a more recent version of the Java Environment Why is ZoneOffset.UTC != ZoneId.of("UTC")? Modify property value of the objects in list using Java 8 streams How to use if-else logic in Java 8 stream forEach Android Studio Error: Error:CreateProcess error=216, This version of %1 is not compatible with the version of Windows you're running Error:could not create the Java Virtual Machine Error:A fatal exception has occured.Program will exit What are functional interfaces used for in Java 8? java.time.format.DateTimeParseException: Text could not be parsed at index 21 Java 8 lambda get and remove element from list

Examples related to java-stream

Sorting a list with stream.sorted() in Java Modify property value of the objects in list using Java 8 streams How to use if-else logic in Java 8 stream forEach Java 8 lambda get and remove element from list Create list of object from another using Java 8 Streams Java 8 Stream API to find Unique Object matching a property value Reverse a comparator in Java 8 Ignore duplicates when producing map using streams Modifying Objects within stream in Java8 while iterating How can I get a List from some class properties with Java 8 Stream?