2

I have seen the following code in many Java 8 reference materials and examples:

List <Integer> l = Arrays.asList(7, 3, 9, 8, 6, 5, -1, -100);  

l.stream().filter(y -> y <l.get(0)).collect(Collectors.toList()).
      forEach(System.out::println);

However, I am able to get the same result using:

l.stream().filter(y -> y <l.get(0)).forEach(System.out::println);

So, what is the sanctity of using collect(Collectors.toList()) that's used almost ubiquitously?

Holger
  • 285,553
  • 42
  • 434
  • 765
Seshadri R
  • 1,192
  • 14
  • 24
  • 11
    *"I have seen the following code in many Java 8 reference materials and examples"* Such as? – T.J. Crowder Nov 27 '17 at 09:38
  • Our good old (and new) Stackoverflow: https://stackoverflow.com/questions/47495381/streams-in-java-cant-figure-it-out – Seshadri R Nov 27 '17 at 09:39
  • 3
    In that example, the end result they want is a List, so of course they use `collect(Collectors.asList())`. – T.J. Crowder Nov 27 '17 at 09:40
  • 5
    That question is not "Java 8 reference material", and it does not show the combined `collect()` and `forEach()` you claim to see "everywhere". – Kayaman Nov 27 '17 at 09:42
  • 1
    Actually, there where so few examples collecting into a list at the beginning, that [a related question was opened on Stackoverflow](https://stackoverflow.com/q/21522341/2711488). Today, that knowledge is common, but *if* you see Stackoverflow questions collecting before printing, it’s likely because that’s *simplified* code omitting the actual processing of the result `Collection` when it’s not relevant to the question. – Holger Nov 27 '17 at 10:54

4 Answers4

9

If all you care about is printing the elements that pass the filter, you don't need collect(Collectors.toList()).

Using ...collect(Collectors.toList()).forEach(System.out::println) is a waste, since it creates a List instance to which you don't keep a reference, and therefore can never access.

Use collect(Collectors.toList()) when you want to create a List of the elements of your Stream. You'd normally keep a reference to that List.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • Question ! What happen when i just want to filter and create some transformation on each element using a map (Example,i want to increment some property) ? I dont want to collect the result ,i just filter and map. – Al Xx Jun 06 '22 at 13:07
  • @AlXx you have to perform some terminal operation in order for the Stream pipeline to be executed on the elements of the Stream. If you don't want to collect the result, you have to choose some other terminal operation, such as `forEach`. – Eran Jun 06 '22 at 15:09
  • Yes i know . But using a forEach ask for a Consumer and i dont need that . I just want filter the array and transform the value . I should use a forEach with a System.out.printl() inside so it gets executed . Do you have another adivce to acomplish this? (Thanks in advance) – Al Xx Jun 06 '22 at 16:21
  • Then what is the difference between - Stream.iterate(1, f -> f+1).limit(5).toList() and Stream.iterate(1, f -> f+1).limit(5).collect(Collectors.toList()) – Yadab Sd Mar 23 '23 at 01:44
3

In this case, collecting the stream to a list is indeed pointless. Collecting should be used to create a list (or set, or map, or whatever) when you actually need a list object explicitly (e.g., in order to pass it on to some other API).

Mureinik
  • 297,002
  • 52
  • 306
  • 350
3

Just looking at the documentation, Stream#forEach is non-deterministic (e.g., you can't know what order the elements will be visited in parallel streams in the general case). So I'd think you'd want to use collect(Collectors.asList()) when you need determinism in terms of the order you visit the elements (or, of course, any other time you want a list) and, of course, not when you don't.

In your specific example, you know the stream isn't parallel, because Collection#stream returns a sequential stream.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 6
    You can use `forEachOrdered(…)` when you want determinism. There’s still no reason for using `collect(Collectors.asList())` when all you want is a deterministic `forEach(…)` – Holger Nov 27 '17 at 10:48
  • @Holger: True, **if** there's an [encounter order](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Ordering) to the stream. (I suspect you're right that people use `collect` when often `forEachOrdered` would be sufficient. For that matter, probably when they don't care about the order at all and could just use `forEach`.) – T.J. Crowder Nov 27 '17 at 10:52
0

Stream.collect(...) & Stream.forEach(...) are the operations to consume the result of the given stream's instance and they do not have any return type. So in your case you do not need both. Use collect(..) method when you need to get the result of stream output in a variable say list and use it later in the application.

Ravik
  • 694
  • 7
  • 12