【问题标题】:Java 8 forEach with index [duplicate]带有索引的Java 8 forEach [重复]
【发布时间】:2016-05-30 16:37:09
【问题描述】:

有没有办法在 Java 8 中构建一个使用索引进行迭代的 forEach 方法?理想情况下,我想要这样的东西:

params.forEach((idx, e) -> query.bind(idx, e));

我现在能做的最好的就是:

int idx = 0;
params.forEach(e -> {
  query.bind(idx, e);
  idx++;
});

【问题讨论】:

  • 如果合并增量 query.bind(idx++, e); 会缩短一行,但这就是我能想到的全部
  • 另外,您不应该能够在该 lambda 中修改 idx
  • @SotiriosDelimanolis 它实际编译
  • 如果idx 是实例变量或其他东西,它会。如果您发布的代码位于方法/构造函数主体中,则不会。
  • @assylias 我投票重新提出这个问题,因为我不认为它与链接的问题完全相同。链接问题的发帖人想在流处理中获取索引,而这个问题的重点只是在(终端)forEach方法中获取索引(基本上是为了替换传统的for循环哪个索引是手动操作的)。我认为我们不应该阻止在这里添加更多答案。实际上,我想提供一个适合这个问题的答案,但不适用于链接的问题。

标签: java for-loop foreach java-8


【解决方案1】:

由于您正在迭代一个可索引的集合(列表等),我认为您可以只使用元素的索引进行迭代:

IntStream.range(0, params.size())
  .forEach(idx ->
    query.bind(
      idx,
      params.get(idx)
    )
  )
;

生成的代码类似于使用经典 i++ 样式的 for 循环迭代列表,除了更容易并行化(当然,假设对 params 的并发只读访问是安全的)。

【讨论】:

  • @TomerCagan 您可以:将索引映射到首选顺序,如果所述顺序可以表示为函数(要反向迭代参数,请使用 IntStream.range(0, params.size( )).map(i -> params.size() - 1 - i)),或者如果特定顺序不是可以从 IntStream.range(0, params. size()),如 Stream.iterate(new int[] {0, 1}, ia -> new int[] {ia[1], ia[0] + ia[1]}).mapToInt(ia -> ia[0]).filter(i -> i
  • 唯一需要考虑的是,当您以这种方式迭代 LinkedList 时,您将得到 O(n^2) 而不是 O(n)
  • 再一次,Java 及其用于简单事物的糟糕语法。
  • java什么时候会提供更简单的替代方案。我想知道
  • 这个答案比int[] idx = { 0 }; params.forEach(e -> query.bind(idx[0]++, e));快吗?
【解决方案2】:

如果您捕获一个包含一个元素的数组,它会与 params 一起使用,该元素包含当前索引。

int[] idx = { 0 };
params.forEach(e -> query.bind(idx[0]++, e));

上面的代码假设方法 forEach 以遇到的顺序遍历元素。 Iterable 接口为所有类指定此行为,除非另有说明。显然它适用于标准库中 Iterable 的所有实现,并且将来更改此行为会破坏向后兼容性。

如果您使用 Streams 而不是 Collections/Iterables,则应该使用 forEachOrdered,因为 forEach 可以同时执行,并且元素可以以不同的顺序出现。以下代码适用于顺序流和并行流:

int[] idx = { 0 };
params.stream().forEachOrdered(e -> query.bind(idx[0]++, e));

【讨论】:

  • 最好使用AtomicInteger,而不是使用int[] 数组。这也将确保如果遇到乱序的元素,我们至少会获得每个元素的唯一索引。
  • @BrettRyan:我不同意。 AtomicInteger表达了错误的意图,效率较低,这种情况下保证了顺序执行
  • Apache lang 库中的 MutableInt 不能正常工作吗?如果使用 forEachOrdered,它不需要是同步结构,对吗?
  • @Skychan:MutableInt 在这种情况下没有帮助,因为它缺少一些操作。特别是像getAndIncrement.
  • @nosid 我不认为使用int[]AtomicInteger 更能揭示意图。如果性能是一个问题,也许 for 循环会更好,因为它避免了 Stream 机制,这可能会使高度优化的 Atomic* 类相形见绌。
【解决方案3】:

有一些变通方法,但没有干净/简短/甜蜜的方式来处理流,老实说,你可能会更好:

int idx = 0;
for (Param p : params) query.bind(idx++, p);

或旧样式:

for (int idx = 0; idx < params.size(); idx++) query.bind(idx, params.get(idx));

【讨论】:

  • 迟到但完全同意。当需要索引时,普通的 for 循环就足够了。
  • @Vortex 更具可读性。
猜你喜欢
  • 1970-01-01
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
相关资源
最近更新 更多