Proposal: JDK-8148917 Enhanced-For Statement Should Allow Streams

Stuart Marks stuart.marks at oracle.com
Fri Mar 1 23:25:24 UTC 2019


> The proposal looks good to me. In particular it's very nice to have
> this properly (ability to iterate only once) to be encoded in the type
> system. This could be helpful for static analysis tools to warn when
> IterableOnce is reused.

Thanks! It would be good to see what you can come up with respect to static 
analysis. I had speculated about this some, but you're much closer to this than 
I am.

> Scanner case looks funny. In general such pattern could be applied to
> every Iterator implementor.

Yes, Scanner is rather an outlier with respect to Iterator. There are of course 
a lot of Iterator implementations, but (at least in the JDK) most of them are 
internal classes that can only be instantiated by calling a method -- typically 
but not always the iterator() method. There are only a few cases where an API 
*class* implements Iterator and where it's likely that calling code would get an 
instance of Iterator separately from iterating over it. Scanner was the only one 
I found in the JDK where it seemed reasonable to want to iterate it using an 
enhanced-for loop.

> As for Streams, I worry a little that people would prefer for(T t :
> stream) {...} over stream.forEach(t -> ...) even when forEach works
> perfectly.

Possibly. Of all the stream operations, forEach() is the one that's the easiest 
to learn but among the least useful. There's a certain kind of error where 
someone new to streams will try to put too much work into a forEach() operation 
and be frustrated because they can't modify local variables, break early, etc. 
The usual remedy is to recast such tasks to use reduction instead. I guess the 
risk is that the person would instead switch to a for-loop and then conclude, 
Why bother with this streams stuff?

I think at this point there are enough streams tutorials and Stack Overflow Q&A 
on this topic that this won't be a very big problem.

> The Stream.iterator() implementation produces some amount
> of unnecessary garbage. At least it would be nice to add special case
> into Spliterators#iterator(java.util.Spliterator<? extends T>) to
> reduce number of wrappers if stream was directly created from an
> iterator or collection: ...
> Of course this could be done later as separate enhancement.

Yes, I think this would be good to investigate and optimize if it proves to be a 
problem.

On 2/28/19 9:54 PM, Tagir Valeev wrote:
> One more alternative which could be considered (though it requires a
> language change) is to allow the inference of Iterable<T> type for
> enhanced for when iteration value is a function expression and
> iteration parameter type is explicitly specified as T. In this case
> for(T t : stream::iterator) {} would be a valid syntax. Also people
> could use enhanced for with any iterator they already have like for(T
> t : () -> iterator) {}. Instead of for (; it.hasNext() ; ) { T t =
> it.next(); ... }. It looks better than allowing to specify iterator
> directly (like for(T t : stream.iterator())) as this could break some
> programs where the same class implements Iterator and Iterable.

This was noticed and discussed fairly early on (way back in 2012!) and it turns 
out to be more complicated than it appears at first glance. See these threads 
from lambda-dev:

     http://mail.openjdk.java.net/pipermail/lambda-dev/2012-August/005717.html

     http://mail.openjdk.java.net/pipermail/lambda-dev/2012-September/005749.html

See in particular the messages from Maurizio. There is also reference to the 
original Java 5 design discussions that ruled out Iterator in the RHS of the 
enhanced-for loop. TL;DR the reason is that they didn't want the RHS expression 
to have a side effect of draining the Iterator.

s'marks



More information about the core-libs-dev mailing list