带有索引的Java 8 forEach

Jos*_*one 129 java foreach for-loop java-8

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

params.forEach((idx, e) -> query.bind(idx, e));
Run Code Online (Sandbox Code Playgroud)

我现在能做的最好的事情是:

int idx = 0;
params.forEach(e -> {
  query.bind(idx, e);
  idx++;
});
Run Code Online (Sandbox Code Playgroud)

srb*_*gan 150

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

IntStream.range(0, params.size())
  .forEach(idx ->
    query.bind(
      idx,
      params.get(idx)
    )
  )
;
Run Code Online (Sandbox Code Playgroud)

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

  • 再一次,Java及其简单的语法可怕的语法. (6认同)
  • 唯一的考虑因素是,当你以这种方式迭代一个LinkedList时,你将得到O(n2)而不是O(n) (3认同)
  • 这个答案比 `int[] idx = { 0 }; 更快吗?params.forEach(e -> query.bind(idx[0]++, e));` ? (2认同)

nos*_*sid 58

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

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

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

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

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

  • 而不是使用`int []`数组,最好使用[AtomicInteger](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html).这也将确保如果无序地遇到元素,我们至少为每个元素获得一个唯一索引. (4认同)
  • @nosid我不认为使用`int []`比'AtomicInteger`更有意思.如果性能是一个问题,也许for循环更好,因为它避免了`Stream`机制,它可能使高度优化的`Atomic*'类相形见绌. (2认同)

ass*_*ias 34

有一些解决方法,但没有干净/简短/甜蜜的方式与流做这件事,说实话,你可能会更好:

int idx = 0;
for (Param p : params) query.bind(idx++, p);
Run Code Online (Sandbox Code Playgroud)

  • 迟到但完全同意。当需要索引时,普通的 for 循环就足够了。 (4认同)
  • @Vortex 并且更具可读性。 (4认同)