1

In java 8, I am using Streams to print the output, but size is coming as 0. Why?

public class IntermediateryAndFinal {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("one", "two", "three", "four", "five");

        Predicate<String> p1 = Predicate.isEqual("two");
        Predicate<String> p2 = Predicate.isEqual("three");

        List<String> list = new ArrayList<>();

        stream.peek(System.out::println)
            .filter(p1.or(p2))
            .peek(list::add);
        System.out.println("Size = "+list.size());
    }
}
Naman
  • 27,789
  • 26
  • 218
  • 353
PAA
  • 1
  • 46
  • 174
  • 282

4 Answers4

5

Ideally you should not mutate an external list, instead you can use Collectors.toList() to collect it in a list:

List<String> list = stream.peek(System.out::println)
            .filter(p1.or(p2))
            .collect(Collectors.toList()); // triggers the evaluation of the stream
System.out.println("Size = "+list.size());

In your example, streams are evaluated only when a terminal operation like

allMatch()
anyMatch() 
noneMatch() 
collect() 
count() 
forEach() 
min() 
max() 
reduce()

are encountered.

Naman
  • 27,789
  • 26
  • 218
  • 353
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
2

Since you haven't yet completed the stream operation i.e. peek is an intermediate operation. You must use a terminal operation for that to be executed still.

Suggestion: Instead perform such operation using terminal operation such as collect

List<String> list = stream.peek(System.out::println)
        .filter(p1.or(p2))
        .collect(Collectors.toList());

Additionally: Adding a peek post filter to observe the values could be a little tricky in observation, as for the following code

List<String> list = stream.peek(System.out::println)
        .filter(p1.or(p2))
        .peek(System.out::println) // addition
        .collect(Collectors.toList());

the output would look like :

one
two
two // filtered in
three
three // filtered in
four
five
Naman
  • 27,789
  • 26
  • 218
  • 353
1

The streams are lazy. You mast call a terminal operation like forEach:

stream.peek(System.out::println)
      .filter(p1.or(p2))
      .forEach(list::add);

In case you want to use peek as intermediary operation for debugging purposes then you must call a terminal operation afterwards:

stream.peek(System.out::println)
      .filter(p1.or(p2))
      .peek(list::add);
      .<any terminal operation here>();

Btw, if you want just store all the filtered values in a list, then better use collect(toList()).

ETO
  • 6,970
  • 1
  • 20
  • 37
  • operations such as modifications of data structures should be avoided in terminal operations (`forEach`) and in the latter approach, there is chance of peek not being executed, for e.g. Java-9 and above implementation of `count()`. – Naman Feb 04 '19 at 05:03
  • For further details refer to https://stackoverflow.com/questions/48221783/stream-peek-method-in-java-8-vs-java-9 – Naman Feb 04 '19 at 05:10
  • @nullpointer Yes, indeed. I was answering the OP's question *"Why?"*. So the answer is in the very first line. But of course I always recommend avoiding mutation of state while processing streams. – ETO Feb 04 '19 at 05:12
0

All you've done with filter and peek is set up a chain of actions to apply to the stream. You haven't actually caused any of them to run yet. You have to add a terminal operation such as count. (Another answer suggested using forEach to add to the list, but I think you're specifically trying to use the intermediate operation peek.)

Willis Blackburn
  • 8,068
  • 19
  • 36
  • 1
    there is a chance of `peek` not being executed, for e.g. Java-9 and above implementation of `count()`. Further details - https://stackoverflow.com/questions/48221783/stream-peek-method-in-java-8-vs-java-9 – Naman Feb 04 '19 at 05:10
  • 1
    Thanks. Learn something new every day! – Willis Blackburn Feb 04 '19 at 05:14