2

I was reading this book called Modern Java in Action and one part of code I could not comprehend.

      IntStream.iterate(0, n -> n + 4)
                .filter(n -> n < 100)
                .forEach(System.out::println);

Authors says that code will not terminate. The reason is that there’s no way to know in the filter that the numbers continue to increase, so it keeps on filtering them infinitely!

I did not get the reason. Could someone explain it why.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
Rakesh Chauhan
  • 413
  • 4
  • 7
  • 4
    why is this post closed? the question is clear... OP wants more clarity on "why does this stream not terminate" – Ousmane D. Jun 09 '20 at 16:20
  • 1
    @Rakesh - Could you elaborate, which part in the specified reason did you not understand? – Naman Jun 09 '20 at 17:19
  • 1
    That’s actually a bad example, as the `int` value will overflow (very soon in up-to-date environments) and loop through the `int` data range forever. It should be clear that skipping the `[100‑Integer.MAX_VALUE]` range will not change the infinite nature of the iteration. A better example would be `Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.TWO)) .filter(n -> n.compareTo(BigInteger.valueOf(100)) < 0) .forEach(System.out::println);`. But even `IntStream.generate(() -> 42) .filter(n -> false) .forEach(System.out::println);` will loop forever, despite not having any perceivable result. – Holger Jun 10 '20 at 07:43
  • @Holger: My intension is to ask why it doesn't stop and I believe this example is good enough. – Rakesh Chauhan Jun 10 '20 at 09:05
  • 1
    But why should it stop? The source stream is infinite and `filter` only tells to skip nonmatching elements. The only reason to assume that it could stop, would be the assumption that no elements can occur after crossing the `n < 100` threshold. And that would be flat wrong as keeping on incrementing the `int` value will overflow and there *are* elements after crossing the threshold. When it comes to the Stream API, my `BigInteger` example will illustrate the issue better, as it shows that even if there truly will be no elements after crossing the threshold, the Stream will keep on testing. – Holger Jun 10 '20 at 11:12

2 Answers2

1

Authors says that code will not terminate.

Yes, because this specific overload of iterate

static IntStream iterate(int seed,
                         IntUnaryOperator f)

Returns an infinite sequential ordered IntStream produced by iterative application of a function f to an initial element seed, producing a Stream consisting of seed, f(seed), f(f(seed)), etc.

returns an infinite stream and given it's an infinite stream it means it can only be terminated via certain operations.

Given the terminal operation in use here (forEach) is not short-circuiting it means that you require a "short-circuiting intermediate operation" to truncate the infinite stream in this specific case e.g. limit (JDK8),takeWhile (JDK9) et al.

The only short-circuiting intermediate operation in JDK8 is limit as it allows computations on infinite streams to complete in finite time.

The reason is that there’s no way to know in the filter that the numbers continue to increase, so it keeps on filtering them infinitely!

filter itself is not a short-circuiting intermediate operation hence cannot terminate a stream. filter's job is essentially to return a stream consisting of the elements of the stream that match the given predicate.

Conclusion: if one is using an infinite stream which does not have a short-circuiting terminal operation then it requires a short-circuiting intermediate operation to truncate the stream else the stream remains infinite.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
0

The int stream will generate a sequence of numbers that start from 0 and have step of 4. Then they will be filtered out. The Int keep generating because there is no terminal condition. It equivalent to

for(int n=0;;n=n+4){... Filter out }