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

Georgiy Rakov georgiy.rakov at oracle.com
Thu Feb 21 02:08:37 PST 2013


Could you please provide some more information regarding following part 
of this spec:

      * Produce a {@code Stream} containing the elements of this stream, 
and also provide elements
      * to the specified {@link Consumer} as elements are consumed from 
the /_*resulting stream*_/.  This is


What is "*resulting stream*" - stream returned by peek() or the stream 
the peek() is applied to, i.e. considering following code - s1 or s2?

    Stream s1;
    ...
    Stream s2 = s1.peek();

Thanks,
Georgiy.

On 20.02.2013 20:38, Brian Goetz wrote:
> Here's the current spec for this method -- does this help?
>
>     /**
>      * Produce a {@code Stream} containing the elements of this 
> stream, and also provide elements
>      * to the specified {@link Consumer} as elements are consumed from 
> the resulting stream.  This is
>      * an <a href="package-summary.html#StreamOps">intermediate 
> operation</a>.
>      * {@apiNote}
>      * This method exists mainly to support debugging, where you want 
> to see the elements as they flow past a certain
>      * point in a pipeline:
>      * <pre>
>      *     list.stream()
>      *         .filter(filteringFunction)
>      *         .peek(e -> {System.out.println("Filtered value: " + e); 
> });
>      *         .map(mappingFunction)
>      *         .peek(e -> {System.out.println("Mapped value: " + e); });
>      *         .collect(Collectors.intoList());
>      * </pre>
>      *
>      * <p>For parallel stream pipelines, the {@code Consumer} may be 
> called at whatever time and in whatever thread
>      * the element is made available by the upstream operation. If the 
> {@code Consumer} modifies shared state,
>      * it is responsible for providing the required synchronization.
>      *
>      * @param consumer The {@code Consumer} to receive the elements
>      */
>
>
>
> On 2/20/2013 10:02 AM, Georgiy Rakov wrote:
>> 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