简体   繁体   中英

Why doesn't Stream.limit work as expected in this snippet?

List<Integer> integer = Stream.generate(new Supplier<Integer>() {
    int i = 0 ;

    @Override
    public Integer get() {
        return ++i;
    }
}).filter(j -> j < 5)
  .limit(10)   // Note the call to limit here
  .collect(Collectors.toList());

Counter to my expectation, the collect call never returns. Setting limit before filter produces the expected result. Why?

Since there are only 4 elements that pass the filter, limit(10) never reaches 10 elements, so the Stream pipeline keeps generating new elements and feeding them to the filter, trying to reach 10 elements that pass the filter, but since only the first 4 elements pass the filter, the processing never ends (at least until i overflows).

The Stream pipeline is not smart enough to know that no more elements can pass the filter, so it keeps processing new elements.

Flipping the limit and the filter clauses has different behaviors.

If you put the limit first, the stream will first generate 10 integers [1..10], and then filter them leaving only those smaller than 5.

In the original ordering, with the filter applied first, integers are generated and filtered until you reach 10 elements. This isn't an infinite operator, as i in the supplier will eventually overflow, but it will take a while, especially on a slow computer, to reach MAX_INT .

If you want to stop either if number 5 is reached or 10 elements are collected, there's Stream.takeWhile() method added in Java-9:

List<Integer> integer = Stream.generate(new Supplier<Integer>() {
    int i = 0 ;

    @Override
    public Integer get() {
        return ++i;
    }
}).takeWhile(j -> j < 5).limit(10).collect(Collectors.toList());

It will finish, after the Supplier overflows and starts generating negative numbers. The resulting list will contain:

[1, 2, 3, 4, -2147483648, -2147483647, -2147483646, -2147483645, -2147483644, -2147483643]

The reason for this is in other answers. On my i7 machine it took 40 seconds to complete.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM