如何为要并行处理的Java列表中的每个项目添加索引

时间:2018-07-25 06:03:03

标签: java parallel-processing java-stream

我有一个Rec的列表,我想通过调用某些方法foo()来并行处理它们。

foo()可能会将某些Rec标记为错误,最后所有错误记录均由其索引位置报告(例如,“记录12无效”)。
所以我想将每个Rec的索引位置传递给foo(),或者在调用foo之前将索引设置到每个Rec中。
我尝试执行的操作(如下所示)是先按顺序将索引设置为每个Rec, 然后并行调用每个foo。有更好的方法吗?

List<Rec> recs;
class Rec {
    private int recordIndex;
    public void setRecordIndex( int index) { recordIndex = index; }
    //more memebers and getter to the above...
}

//somewhere in the code
int index = 0;
recs.stream().forEach(rec -> rec.setRecordIndex(index++));
//the compiler complains about the index++ above, says it should be final
rec.parallelStream().forEach(rec -> foo(ProgressInfo, rec));

是否总体上有更好的方法?如果没有,有没有办法解决编译错误并仍然使用流? (而不是循环)

2 个答案:

答案 0 :(得分:2)

这可以通过IntStream完成,我也建议仅使用一个Stream

IntStream.range(0, recs.size())
    .mapToObj(i -> {
       Rec rec = recs.get(i);
       rec.setRecordIndex(i);
       return rec;
    })
    .parallel()
    .forEach(rec -> foo(ProgressInfo, rec));

尽管不建议在streams中修改状态,所以与其将index设置在mapToObj内,不如返回一个新对象。例如。像这样的东西:

.mapToObj(i -> {
   Rec copy = new Rec(recs.get(i)); // copy constructor
   copy.setRecordIndex(i);
   return copy;
})

根据您使用的List实现(使用 index-access 时,ArrayList的效果要优于LinkedList),也可以使用以下代码段。但是在生产代码中使用peek有点争议。

IntStream.range(0, recs.size())
   .peek(i -> recs.get(i).setRecordIndex(i))
   .parallel()
   .forEach(i -> foo(ProgressInfo, recs.get(i));

答案 1 :(得分:1)

您可以使用IntStream

IntStream.range(0, recs.size())
         .forEach(i -> recs.get(i).setRecordIndex(i));

这只是使用从0recs.size() - 1的数字流,并为每个数字调用recs.get