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

How to convert normal for loop to parallel stream in java

我正在尝试将迭代 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;
}

我尝试使用以下代码,但它给我的错误是“”newList should be final”。

    finPlanIdsList.parallelStream().forEach( planId -> {
            newList.add(retrieveFinPlan(planId));
    });

所以,主要问题是如何将上面的正常循环转换为 parallelStream.forEach() 和 parallelStream().collect() ?

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

您可以尝试这样修复它:

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

...

finPlanIdsList.parallelStream().forEach( planId -> {
        newList.add(retrieveFinPlan(planId));
});

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

正确的解决方法是:

List<FinPlan> newList = 
    finPlanIdsList.parallelStream()
                  .map(planId -> retrieveFinPlan(planId))
                  .collect(Collectors.toList());

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

一般来说,流依赖副作用是个坏主意。在某些情况下,您会侥幸逃脱。在其他……没有。

您的方法定义似乎不正确,因为 getFinPlanList returns 是 FinPlan 而不是 List

此外,您不能在 lambda 表达式中使用不是最终有效的局部变量。因此它不会编译。 您可以尝试使用以下命令生成列表。请注意,应用并行流后,无法保证处理对象的顺序。

return finPlanIdsList.parallelStream().map(finPlanId->retrieveFinPlan(finPlanId)).collect(Collectors.toList());