在Java 8流中没有索引的原因是什么?

时间:2014-04-01 14:49:35

标签: java java-8 java-stream

我想知道Java 8流(Stream<E>),它们有以下方法:

  • forEach(Consumer<? super E> action)
  • forEachOrdered(Consumer<? super E> action)

反对不提供以下签名的理由是什么?

  • forEachOrdered(BiConsumer<Integer, ? super E> action)
    • 然后返回流中项目的索引和项目本身。

使用此重载,可以在订购流时实际使用索引。

我真的很好奇,看看有什么反对意见。

编辑Iterator<E>forEachRemaining实际相同,可能还有更多类。
如果没有类提供这样的选项,那么我怀疑它已被考虑用于Java 8并被拒绝。

4 个答案:

答案 0 :(得分:8)

索引每个元素需要按顺序分配索引。这会破坏并行操作的重点,因为每个操作都必须同步才能获得其索引。

答案 1 :(得分:6)

StreamIterator s不一定是有限的。两个Stream::generate  并Stream::iterate返回无限Stream秒。您将如何使用无限流处理索引?让指数溢出到负数?使用BigInteger(可能内存不足)?

处理无限流的索引并不是一个好的解决方案,因此设计人员(正确地说,在我看来)将其排除在API之外。

答案 2 :(得分:2)

添加提供索引的单个方法需要将所有实现方法加倍,以使一个方法维护一个索引而一个方法没有索引。除了在API中可见之外,它还有更多内容。如果您好奇,可以查看内部接口java.util.stream.Sink<T>的类型树以获得想法。所有这些都会受到影响。另一种方法是即使不需要也始终保持索引。

它增加了含糊不清的含义。索引是否反映了索引,即在过滤时没有改变,或者它是最终流中的位置?另一方面,您始终可以将项目类型的映射插入到包含项目的类型和链中任何位置的索引。这将清除模糊性。该解决方案的局限性与JRE提供的解决方案相同。

如果Iterator,答案更简单。由于forEachRemaining必须作为default接口方法提供,因此无法添加索引的维护。因此,在调用它时,它不知道到目前为止已消耗了多少项。当时以零开始计数,忽略所有先前的项目将成为很多开发人员会质疑的功能。

答案 3 :(得分:0)

我已经阅读了上述所有答案,但是,我个人不同意这些答案。我认为应该添加一些方法(例如indexed())并且它可以顺序执行,即使在并行流中也是如此,因为这种方法将快速验证,不需要并行执行。您可以按地图添加“索引”。例如:

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);

或者您可以使用第三个库:AbacusUtil,代码为:

List<String> list = N.asList("a", "b", "c");
Stream.of(list).indexed().forEach(N::println);
// output:
// [0]=a
// [1]=b
// [2]=c

披露:我是AbacusUtil的开发者。