1

Will the following code filter elements until it find 3 elements that pass the filtering method, or filter all elements?

manyItems.stream()
    .filter(it -> it.getValue > 100)
    .limit(3)
    ...
GBlodgett
  • 12,704
  • 4
  • 31
  • 45
  • 1
    Why not run it and find out? – kjerins Mar 12 '19 at 14:51
  • Read : https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html – Adil Shaikh Mar 12 '19 at 14:53
  • 3
    I recommend reading [my answer here](https://stackoverflow.com/a/32414480/4125191) to understand how this works. Note that your code doesn't have a terminal operation, so it actually does nothing. – RealSkeptic Mar 12 '19 at 14:54
  • //try for urself List list = new ArrayList(); list.add(-2); list.add(0); list.add(2); list.add(4); list.add(6); list.add(8); list.add(10); list.add(12); list.add(14); list.add(16); System.out.println(list.stream().filter(it -> it > 4).limit(3).collect(Collectors.toList())); System.out.println(list.stream().filter(it -> it > 4).collect(Collectors.toList())); – Optional Mar 12 '19 at 14:59
  • @Optional please refrain from putting code in comments. They are not made for this and your code becomes unreadable. – RealSkeptic Mar 12 '19 at 15:29
  • Yes @RealSkeptic I understand that. But since it was not really an answer, I thought it other way. I will keep it in mind in future. – Optional Mar 12 '19 at 15:32
  • @Optional I don’t think that code in comment is bad, but you should keep it short and simple, e.g. use `List list = Arrays.asList(-2, 0, 2, 4, 6, 8, 10, 12, 14, 16);` instead of a long-winded `ArrayList` initialization. And use backticks to mark the code parts, like in compare `list.stream().filter(it -> it>=2).limit(3).forEach(System.out::println);` with `list.stream().filter(it -> it>=2).forEach(System.out::println);` or even `list.stream().limit(3).filter(it -> it>=2).forEach(System.out::println);`… – Holger Mar 13 '19 at 09:22

2 Answers2

2

filter() has lazy execution. This means that it doesn't actually do anything right when you call it. Instead it just returns a new Stream that will contain the elements that match the given Predicate when traversed.

Since limit() is a short-circuiting stateful intermediate operation, it will process the Stream until it reaches the limit and short circuits. This means that when you call filter, it will return a new Stream that contains only the elements, when traversed. Since limit only traverses enough to reach the given size, filter will, in effect, only filter out the required amount of elements.

We can test this by throwing in a call to peek():

Arrays.stream(new int[] {1, 2, 2, 2, 2})
      .filter(e->  e > 1)
      .peek(System.out::println)
      .limit(3)
      .average();      

(Where average() could be any terminal operation that doesn't short circuit on its own)

Which outputs:

2
2
2

(Note that the last two does not appear after the call to filter())

GBlodgett
  • 12,704
  • 4
  • 31
  • 45
  • Small contradiction there: "it will process the *entire* Stream until it reaches the limit and short circuits". If it short circuits, then it won't actually process the *entire* stream. Drop the word "entire". – Andreas Mar 12 '19 at 15:13
0

That method is gonna first apply the filter and then, after that, is gonna call limit on the filtered stream. You can easily try it writing a test.

burm87
  • 768
  • 4
  • 17