skiwi
skiwi

Reputation: 69349

What are the reasons for not having an index in Java 8 streams?

I was wondering about the Java 8 streams (Stream<E>), they have the following methods:

What were the arguments against not supplying the following signature?

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

Answers (4)

user_3380739
user_3380739

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

Holger
Holger

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

aepurniet
aepurniet

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

Jeffrey
Jeffrey

Reputation: 44808

Streams and Iterators do not have to be finite. Both Stream::generate and Stream::iterate return infinite Streams. 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

Related Questions