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

╄→尐↘猪︶ㄣ 提交于 2019-12-18 05:46:13

问题


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)
    • Which would then return the index of the item in the stream and the item itself.

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.


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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: AbacusUtil, 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 AbacusUtil.



来源:https://stackoverflow.com/questions/22789413/what-are-the-reasons-for-not-having-an-index-in-java-8-streams

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!