11

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

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

反对不提供以下签名的论点是什么?

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

有了这个重载,就可以在流被排序的情况下实际使用索引。

我真的很想知道反对它的论点是什么。

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

4

4 回答 4

9

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

于 2014-04-01T15:36:44.587 回答
6

Streams 和Iterators 不必是有限的。两者都Stream::generate 返回Stream::iterate无穷大Stream。您将如何处理无限流的索引?让索引溢出到负数?使用BigInteger(并可能耗尽内存)?

没有一个很好的解决方案来处理无限流的索引,所以设计者(在我看来是正确的)将它排除在 API 之外。

于 2014-04-01T15:07:38.123 回答
2

添加提供索引的单个方法将需要将所有实现方法加倍以使一个维护索引而一个不维护索引。它比 API 中可见的更多。如果你好奇,你可以看看内部接口的类型树来了解一下java.util.stream.Sink<T>。他们都会受到影响。另一种方法是始终维护索引,即使它不是必需的。

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

如果有Iterator答案,那就更简单了。由于forEachRemaining必须作为default接口方法提供它不能添加索引的维护。所以在它被调用的时候,它并不知道到目前为止已经消费了多少项目。并且那时从零开始计数,忽略所有以前的项目将是许多开发人员会更加质疑的功能。

于 2014-04-02T11:31:38.277 回答
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 的开发者。

于 2016-12-07T23:24:20.513 回答