peek().iterator().hasNext() pre-consumes elements?

Georgiy Rakov georgiy.rakov at oracle.com
Wed Feb 20 07:02:35 PST 2013


Hello again,

it has just come into my mind that it could be quite more major issue 
than I wrote in my previous letter.

So the case a bit rewritten:

    Stream s1 = Arrays.asList(1, 2, 3).stream();
    Stream s2 = s1.peek(System.err::println);
    s2.iterator().hasNext();


The spec says:

    Produce a Stream containing the elements of this stream, and also
    provide elements to the specified Consumer as elements are *passed
    through*.

So the core question is what does "passed through" mean?From the first 
glance I would say it means *consuming elements from **stream returned 
****by peek()* (not from stream which peek() is applied to). If this 
interpretation is right then I could suppose it's a bug because the 
element from s2 has not been consumed yet (next() is not called just 
hasNext() has been called).

Could you please confirm if such reasoning is right and it's really a bug.

Thanks, Georgiy.

On 12.02.2013 23:01, Remi Forax wrote:
> On 02/12/2013 07:16 PM, Brian Goetz wrote:
>> The answer here is complicated, but in general, calling hasNext may well
>> require consuming an element -- there's often no way to know whether a
>> source would produce an element without asking it to do so.  So it is a
>> common practice in implementing iterators to do this (one of many
>> reasons why we did not build Streams on Iterator.)
>>
>> Because the elements are coming from an array, it might be possible to
>> know simply based on how many elements have gone by that the stream is
>> not yet exhausted.  But in the general case (such as when the stream
>> source is an IO channel), it is not possible to know without actually
>> consuming and buffering some input.  So I would put this in the category
>> of "acceptable" behavior.  We might someday do some work to take
>> advantage of the fact that the source has the SIZED characteristic and
>> the pipeline stages are size-preserving to make this case behave
>> "better", but that would be an implementation quality issue, not a spec
>> issue.  The behavior you observe is allowable by the spec.
> while I a stream may have to do some buffering, peek should always be
> transparent and an iterator on an array doesn't need any buffering but I
> agree that this is an implementation issue.
>
> Rémi
>
>> On 2/12/2013 12:53 PM, Dmitry Bessonov wrote:
>>> Hello,
>>>
>>> The following line prints out the first element, "1"
>>>
>>>       Arrays.asList(1, 2,
>>> 3).stream().peek(System.err::println).iterator().hasNext()
>>>
>>> Is it really an expected behavior?
>>>
>>> -Dmitry
>>>
>>>
>>>
>



More information about the lambda-dev mailing list