RFR: 8005051: optimized defaults for Iterator.forEachRemaining

Peter Levart peter.levart at gmail.com
Fri Apr 26 14:22:54 UTC 2013

On 04/26/2013 03:06 PM, Remi Forax wrote:
> On 04/26/2013 02:50 PM, Paul Sandoz wrote:
>> On Apr 26, 2013, at 2:06 PM, David Holmes <david.holmes at oracle.com> 
>> wrote:
>>>>>> To avoid blocking the feature, I have filed
>>>>>> https://jbs.oracle.com/bugs/browse/JDK-8013150 to refine the 
>>>>>> behavior of remove and other ListIterator methods after 
>>>>>> forEachRemaining returns.
>>>>> I think the fact that the last element can be removed should be 
>>>>> specified as unspecified,
>>>>> because it's more an artefact of the default implementation than 
>>>>> something which part
>>>>> of the semantics.
>>>> I was wondering about that too. What happens if an implementing 
>>>> class decides later on to override the default implementation? If 
>>>> the overriding implementation does not conform to the same 
>>>> behaviour as the default it could break compatibility.
>>>> Plus one could change code from:
>>>>    while(it.hasNext() { doSomething(it.next()); }
>>>>    doSomethingAtEnd(it);
>>>> to
>>>>    it.forEachRemaining(this::doSomething}
>>>>    doSomethingAtEnd(it);
>>> All implementations must obey the contract of the specification, and 
>>> no clients should assume any kind of behaviour beyond what that 
>>> contract says.
>>> That said I've lost the context of this particular issue - what is 
>>> the problem here?
>> What is the state of the Iterator after a call to 
>> Iterator.forEachRemaining e.g.:
>>    void doSometingAtEnd(Iterator it) {
>>      it.remove();
>>    }
>> IMO overriding forEachRemaining implementations should place the 
>> iterator in the same state as the default method implementation. We 
>> just need to call this out more clearly in the docs.
> I don't like the fact that the default implementation dictates the 
> semantics of forEachRemaining.
> It's cleaner to separate the two and says that you can replace the 
> while loop by forEachRemaining
> only if the iterator is not used after the while loop.
> Basically, it means that the semantics of forEachRemaining is more 
> like the semantics of the enhanced for loop.

... which is based on Iterable, not Iterator (the Iterator is not 
accessible in the foreach).

Do you think there could be implementations that are more optimal if 
this is not dictated? If the same object provides an API for both 
internal and external iteration and the internal iteration can continue 
where the external left-off, then it must always be prepared to maintain 
the state for external iteration, so it's not a big deal to update this 
state once at the end of internal iteration. Do you imagine a situation 
where this would actually provide to be difficult or less performant?

What about the following:

Iterator<?> i = ...;

i.forEachRemaining(e -> {...});

i.forEachRemaining(e -> {...});

would the second call to forEachRemaining be specified to not be defined 

Another interesting question. What about the following usage:

Iterator<?> i = ...;

i.forEachRemaining(e -> {
    if (.. && i.hasNext()) i.next(); // skip one element

Should this be allowed and work as "expected", disallowed and attempted 
to be prevented, or not defined ?

Regards, Peter

>> Paul.
> Rémi

More information about the core-libs-dev mailing list