Hi Pavel,

I think you've raised a critical point.

My impression of the Stream specification is that it defines the order of
inputs and outputs but refrains from strictly defining the order of
execution.

Specifically, the stream guarantees it will call iterate() to produce
elements in encounter order (e.g., 1 and 2) and send them to takeWhile() in
the same order. However, does it actually promise a sequence of iterate()
-> takeWhile() -> iterate() -> takeWhile()? Or could it execute as
iterate() -> iterate() -> takeWhile() -> takeWhile()?

I believe both orders conform to the spec, but the latter would result in a
NullPointerException. Does that distinction make sense?

Best,

Jige Yu

On Sun, Mar 1, 2026 at 2:56 PM Pavel Rappo <[email protected]> wrote:

> I'm neither an expert in streams nor an everyday user. So take this
> with a grain of salt.
>
> What you seem to want has nothing to do with happens-before.
> Happens-before is about memory model. What you want is a guarantee
> that iterate() will not be called after it has produced null, because
> doing so would mean your idiom is buggy.
>
> I think you have that guarantee. iterate() produces a sequential
> ordered stream. takeWhile() is an intermediate operation, and it does
> not change whether the stream is parallel or sequential. Unless you
> insert parallel() between these two calls, a terminal operation will
> not cause iterate() to produce more than one null element because
> streams are lazy. Put differently, you should never see a
> NullPointerException thrown from your snippet. That's my
> understanding.
>
> FWIW, there's a fused overload of iterate() that additionally takes
> the termination condition that your snippet passes to takeWhile(). It
> will behave correctly and similarly to your snippet even if the stream
> is later parallelized.
>
> On Sun, Mar 1, 2026 at 5:29 AM Jige Yu <[email protected]> wrote:
> >
> > Hi @core-libs-dev,
> >
> > I am looking to validate the following idiom:
> >
> > Stream.iterate(seed, e -> e.nextOrNull())
> >     .takeWhile(Objects::nonNull);
> >
> > The intent is for the stream to call nextOrNull() repeatedly until it
> returns null. However, I am concerned about where the Stream specification
> guarantees the correctness of this approach regarding happens-before
> relationships.
> >
> > The iterate() Javadoc defines happens-before for the function passed to
> it, stating that the action of applying f for one element happens-before
> the action of applying it for subsequent elements. However, it seems silent
> on the happens-before relationship with downstream operations like
> takeWhile().
> >
> > My concern stems from the general discouragement of side effects in
> stream operations. For example, relying on side effects between subsequent
> map() calls is considered brittle because a stream might invoke the first
> map() on multiple elements before the second map() processes the first
> element.
> >
> > If this theory holds, is there anything theoretically preventing
> iterate() from generating multiple elements before takeWhile() evaluates
> the first one? I may be overthinking this, but I would appreciate your
> insights into why side effects are discouraged even in ordered, sequential
> streams and whether this specific idiom is safe.
> >
> > Appreciate your help!
> >
> > Best regards,
> > Jige Yu
>

Reply via email to