带有索引的Java 8 forEach [重复]
Posted
技术标签:
【中文标题】带有索引的Java 8 forEach [重复]【英文标题】:Java 8 forEach with index [duplicate] 【发布时间】:2014-05-12 15:32:18 【问题描述】:有没有办法在 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循环在哪个索引是手动操作的)。我认为我们不应该阻止在这里添加更多答案。实际上,我想提供一个适合这个问题的答案,但不适用于链接的问题。
【参考方案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 更具可读性。以上是关于带有索引的Java 8 forEach [重复]的主要内容,如果未能解决你的问题,请参考以下文章
使用java 8中的forEach(..)而不是java 5中的forEach循环的任何优势[重复]