执行并行Stream Java 8时获取异常

时间:2019-10-14 19:25:35

标签: java java-8 nullpointerexception java-stream

我正在编写一个函数,用于计算给定数字的数字平方和。我正在为1到1000之间的数字并行调用此函数。但是我有一段时间会例外。

public static void main(String[] args) throws Exception {
    IntStream stream = IntStream.rangeClosed(1, 1000);
    Map < Integer, Integer > numbers = new TreeMap < > ();
    stream.parallel().forEach(i - > {
        int result = digitSquareSum(i);
        numbers.put(i, result);
    });
    Files.write(Paths.get("result.csv"), () - > numbers.entrySet().stream()
        . < CharSequence > map(e - > e.getKey() + "," + e.getValue())
        .iterator());
}

private static int digitSquareSum(int i) {
    int result = 0;
    int temp = 0;
    while (i != 0) {
        temp = i % 10;
        result = result + temp * temp;
        i = i / 10;
    }
    return result;
}

我正在跟踪异常

Exception in thread "main" java.lang.NullPointerException
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
    at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:590)
    at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:668)
    at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:726)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:189)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
    at java.base/java.util.stream.IntPipeline.forEach(IntPipeline.java:417)
    at java.base/java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:574)

我的目标是编写一种有效的方法,该方法可以计算数字的数字平方和,然后将其以升序方式写入csv文件。

1 个答案:

答案 0 :(得分:1)

如注释中所述,您将收到此异常,因为TreeMap不是线程安全的。来自javadoc

  

请注意,此实现未同步。如果有多个线程   同时访问地图,并且至少有一个线程修改了   从结构上讲,地图必须在外部进行同步。 (一种   结构修改是添加或删除一个或多个   更多映射;仅更改与现有产品关联的值   关键不是结构上的修改。)

我相信您正在使用TreeMap来保留初始数字的顺序。但这不是必需的(并且还引入了side-effects):您可以使用Collectors.toList(),它按遇到的顺序将所有输入元素收集到一个列表中

这还将使您避免创建第二个流,以将这些数字写入文件:

List<String> lines = IntStream.rangeClosed(1, 1000)
            .parallel()
            .mapToObj(i -> i + " -> " + digitSquareSum(i))
            .collect(Collectors.toList());
Files.write(Paths.get("result.csv", lines); // the lines will come in the right order