java中如何将普通的for循环转换为并行流

Mas*_*aza 1 java parallel-processing java-8 parallel.foreach

我正在尝试将迭代 ArrayList 的普通 for 循环转换为并行循环。我遇到了parallelStream.forEach() 和parallelStream().collect(Collectors.toList()) 的概念。但不清楚如何转换。下面是普通 for 循环的示例代码:

public List<FinPlan> getFinPlanList() {
List<FinPlan> newList = new ArrayList<>();

// get list of string   
List<String> finPlanIdsList = finPlanSearchRequest.getFinPlanIds();

// iterate list and add element to new list
    for(String planId: finPlanIdsList) {
    
        newList.add(retrieveFinPlan(planId));
    }
    
    return newList;
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用以下代码,但它给了我错误“newList 应该是最终的”。

    finPlanIdsList.parallelStream().forEach( planId -> {
            newList.add(retrieveFinPlan(planId));
    });
Run Code Online (Sandbox Code Playgroud)

那么,主要问题是如何将上面的普通循环转换为parallelStream.forEach()和parallelStream().collect()?

Ste*_*n C 5

当前版本中发生编译错误的原因是 lambda 表达式不允许使用final在创建 lambda 时既不是最终的也不是有效的局部变量。

你可以尝试这样修复它:

final List<FinPlan> = new ArrayList<>();

...

finPlanIdsList.parallelStream().forEach( planId -> {
        newList.add(retrieveFinPlan(planId));
});
Run Code Online (Sandbox Code Playgroud)

...但这有一个更微妙的缺陷,即代码不是线程安全的。该newList对象可能会从不同的线程更新......并且ArrayList不是线程安全的类。

正确的解决方案是这样的:

List<FinPlan> newList = 
    finPlanIdsList.parallelStream()
                  .map(planId -> retrieveFinPlan(planId))
                  .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

如果结果必须为ArrayList,则可以将Collectors.toList()表达式替换为Collections.toCollection(ArrayList::new)

一般来说,流依赖副作用是一个坏主意。在某些情况下,你会侥幸逃脱惩罚。在其他方面……不。