Reputation: 69349
I was wondering about the Java 8 streams (Stream<E>
), they have the following methods:
forEach(Consumer<? super E> action)
forEachOrdered(Consumer<? super E> action)
What were the arguments against not supplying the following signature?
forEachOrdered(BiConsumer<Integer, ? super E> action)
With this overload it would be possible to actually use the index in case the stream was ordered.
I am really curious to see what the arguments are against it.
Edit, the same actually holds for Iterator<E>
with forEachRemaining
, and possibly more classes.
If none of the classes provide such option, then I suspect it has been considered for Java 8 and denied.
Upvotes: 12
Views: 1690
Reputation: 1254
I have read all above answers, however, personally i disagree with them. I think some method(e.g. indexed()) should be added and it can be executed sequentially, even in parallel stream because this method will be verify fast, no need to execute in parallel. You can add 'index' by map. for example:
List<String> list = N.asList("a", "b", "c");
final AtomicLong idx = new AtomicLong(0);
list.stream().map(e -> Indexed.of(idx.getAndIncrement(), e)).forEach(N::println);
Or you can use third library: abacus-common, the code will be:
List<String> list = N.asList("a", "b", "c");
Stream.of(list).indexed().forEach(N::println);
// output:
// [0]=a
// [1]=b
// [2]=c
Disclosure: I'm the developer of abacus-common.
Upvotes: 0
Reputation: 298389
Adding a single method providing an index would require all implementation methods to be doubled to have one maintaining an index and one without. There’s more to it than visible in the API. If you are curious you may look at the type tree of the internal interface java.util.stream.Sink<T>
to get an idea. All of them would be affected. The alternative would be to always maintain an index even if it is not required.
And it adds an ambiguity. Does the index reflect the source index, i.e. does not change on filtering, or is it a position in the final stream? On the other hand you can always insert a mapping from an item type to a type holding the item and an index at any places in the chain. This would clear the ambiguity. And the limitations to that solution are the same that a JRE provided solution would have.
In case of an Iterator
the answer is even simpler. Since forEachRemaining
must be provided as a default
interface method it cannot add the maintenance of an index. So at the time it is invoked, it doesn’t know how many items have been consumed so far. And starting the count with zero at that time, ignoring all previous items would be a feature that a lot of developers would question even more.
Upvotes: 2
Reputation: 1727
indexing every element requires a sequential assignment of the indexes. this would defeat the point of parallel operations, since each operation would have to synchronize to get its index.
Upvotes: 9
Reputation: 44808
Stream
s and Iterator
s do not have to be finite. Both Stream::generate
and Stream::iterate
return infinite Stream
s. How would you handle indexing with an infinite stream? Let the index overflow to negative numbers? Use a BigInteger
(and potentially run out of memory)?
There isn't a good solution to handling indexing for infinite streams, so the designers (correctly, in my opinion) left it out of the API.
Upvotes: 6