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

387,579

Solution 1

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

Solution 2

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

Solution 3

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.

Solution 4

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/

Solution 5

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

List<Long> targetLongList = sourceLongList
         .stream()
         .filter(l -> l > 100)
         .toList();
Share:
387,579
Daniel K.
Author by

Daniel K.

Updated on July 08, 2022

Comments

  • Daniel K.
    Daniel K. almost 2 years

    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?

  • orbfish
    orbfish almost 9 years
    This is, however, useful if you want a particular List implementation.
  • Eduard Korenschi
    Eduard Korenschi over 8 years
    Despite beeing recommended to code against interfaces, there are clear cases (one of them being GWT) when you have to code against concrete implementations (unless you want all List implementations compiled and delivered as javascript).
  • Lii
    Lii almost 8 years
    Addition: I think this codes gets a little shorter, clearer and prettier if you use a static import of toList. This is done by placing the following among the imports of the file: static import java.util.stream.Collectors.toList;. Then the collect call reads just .collect(toList()).
  • Lii
    Lii almost 8 years
    In Eclipse it is possible to make the IDE add a static import for methods. This is done by adding the Collectors class in Preferences -> Java -> Editor -> Content Assist -> Favorites. After this, you only have to type toLi at hit Ctr+Space to have the IDE fill in toList and add the static import.
  • Daniel K.
    Daniel K. over 7 years
    I don't like that the collect() is only used to drive the stream so that the peek() hook is called on each item. The result of the terminal operation is discarded.
  • Lii
    Lii over 7 years
    It is very weird to call collect and then not save the return value. In that case you could use forEach instead. But that is still a poor solution.
  • Lluis Martinez
    Lluis Martinez about 7 years
    If you declare result as List<Long> you don't need to use this util method. Collectors.toList will do. Also, using specific classes instead of interfaces is a code smell.
  • Lii
    Lii about 7 years
    @LluisMartinez: "Collectors.toList will do.": No, not in many situations. Because it's not a good idea to use toList if you for example want to modify the list later in the program. The toList documentation says this: "There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned; if more control over the returned List is required, use toCollection.". My answer demonstrates a way to make it more convenient to do that in a common case.
  • Lluis Martinez
    Lluis Martinez about 7 years
    If you want to specifically create an ArrayList then it's ok.
  • Grzegorz Piwowarek
    Grzegorz Piwowarek almost 7 years
    Using peek() in this way is an antipattern.
  • Mutant Bob
    Mutant Bob over 6 years
    One thing to keep in mind is that IntStream and some other almost-but-not-quite-Streams do not have the collect(Collector) method and you will have to call IntStream.boxed() to convert them to a regular Stream first. Then again, maybe you just want toArray() .
  • Charles Wood
    Charles Wood over 6 years
    Another pro for this method, from the Collectors::toList javadoc: "There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned; if more control over the returned List is required, use toCollection(Supplier)."
  • amarnath harish
    amarnath harish over 5 years
    why we have to use sequential() before forEach or use 'forEachOrdered`
  • Maurice Naftalin
    Maurice Naftalin over 5 years
    @amarnathharish Because forEach doesn't guarantee the order of operation execution for a parallel stream. The JavaDoc says "The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism." (The first sentence of this quote actually means that order is not guaranteed for sequential streams either, although in practice it is preserved.)
  • Vaneet Kataria
    Vaneet Kataria over 5 years
    As per Stream Java docs peek method must be used for debugging purposes only .It should not be used for any processing other than debugging .
  • Vaneet Kataria
    Vaneet Kataria over 5 years
    I don't find any toList method present in LongStream class. Could you run this code ?
  • user_3380739
    user_3380739 over 5 years
    @VaneetKataria try com.landawn.abacus.util.stream.LongStream or LongStreamEx in AbacusUtil
  • B--rian
    B--rian almost 5 years
    Thanks for your input. However, please explain what you changed and in how far it relates to the question.
  • Pratik Pawar
    Pratik Pawar almost 5 years
    Here firstly I converted my ArrayList to steam them using filter I filter out required data. Finally I have used collect method of java 8 stream to collect data in new list called as targetLongList.
  • Lei Yang
    Lei Yang almost 4 years
    why cannot it be as simple as C# syntax: (some ienumerable).ToList()?