Java8中Lambda表达式的编译器内部错误

4

我正在运行一个小代码来测试Java8 lambda的reduce()功能。我有一个由类型为Person的对象列表组成,其中包含字段nameage。我试图使用Java8的reduce功能找到所有人年龄的总和。以下是代码:

public class Person {

    String name;
    Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


public class TestReduce {
    public static void main(String[] args){
       Person p1 = new Person("P1", 10);
       Person p2 = new Person("P2", 20);
       Person p3 = new Person("P3", 30);

       List<Person> personList = new ArrayList<Person>();
       personList.add(p1);
       personList.add(p2);
       personList.add(p3);

       int sumAge = personList.stream()
                       .reduce(0, (result, person) -> result += person.age, Integer::sum);
    }
}

当我运行上述代码时,尽管我的IDE没有显示任何编译错误,但我仍然收到以下错误。
Using javac 1.8.0_25 to compile java sources
java: An exception has occurred in the compiler (1.8.0_25). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
java: java.lang.NullPointerException
java:   at com.sun.tools.javac.code.Types.isConvertible(Types.java:290)
java:   at com.sun.tools.javac.comp.Check.assertConvertible(Check.java:922)
java:   at com.sun.tools.javac.comp.Check.checkMethod(Check.java:876)
java:   at com.sun.tools.javac.comp.Attr.checkMethod(Attr.java:3838)
java:   at com.sun.tools.javac.comp.Attr.checkIdInternal(Attr.java:3615)
java:   at com.sun.tools.javac.comp.Attr.checkMethodIdInternal(Attr.java:3522)
java:   at com.sun.tools.javac.comp.Attr.checkMethodId(Attr.java:3501)
java:   at com.sun.tools.javac.comp.Attr.checkId(Attr.java:3488)
java:   at com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:3370)
java:   at com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:1897)
java:   at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:607)
java:   at com.sun.tools.javac.comp.Attr.visitApply(Attr.java:1843)
java:   at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1465)
java:   at com.sun.tools.javac.comp.Attr.attribExpr(Attr.java:649)
java:   at com.sun.tools.javac.comp.Attr.visitVarDef(Attr.java:1093)
java:   at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:852)
java:   at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:676)
java:   at com.sun.tools.javac.comp.Attr.attribStats(Attr.java:692)
java:   at com.sun.tools.javac.comp.Attr.visitBlock(Attr.java:1142)
java:   at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:909)
java:   at com.sun.tools.javac.comp.Attr.visitMethodDef(Attr.java:1035)
java:   at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:778)
java:   at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:4342)
java:   at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:4252)
java:   at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:4181)
java:   at com.sun.tools.javac.comp.Attr.attrib(Attr.java:4156)
java:   at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1248)
java:   at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:901)
java:   at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:860)
java:   at com.sun.tools.javac.main.Main.compile(Main.java:523)
java:   at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)
java:   at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)
java:   at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:165)
java:   at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:407)
java:   at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:304)
java:   at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:210)
java:   at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:182)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1106)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:814)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:862)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:777)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:600)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:352)
java:   at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:184)
java:   at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:129)
java:   at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:224)
java:   at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:113)
java:   at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler$1.run(BuildMain.java:157)
java:   at org.jetbrains.jps.service.impl.SharedThreadPoolImpl$1.run(SharedThreadPoolImpl.java:41)
java:   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
java:   at java.util.concurrent.FutureTask.run(FutureTask.java:266)
java:   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java:   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java:   at java.lang.Thread.run(Thread.java:745)
java: Errors occurred while compiling module 'Lambda'
Compilation completed with 1 error and 0 warnings in 2 sec
1 error
0 warnings
Error:java: Compilation failed: internal java compiler error
3个回答

11

这是javac编译器中已知的bug。要么将编译器升级到版本1.8.0_40(或更高版本),要么明确指定lambda参数类型((Integer result, Person person) -> ...)。


这应该是被接受的答案!我遇到了类似的错误(编译器错误,但由于AssertionException而不是NPE),明确指定参数类型可以解决它。在我的情况下,它是一个Class<T>,我只是指定了(Class) c ->,而使用Class<AType> c ->修复了它。 - jrf

2
尽管Tagir的回答更直接地回答了你关于编译器错误的问题,但值得指出的是,有一种更好的编写解决方案的方法,不仅更简洁、更清晰,而且不会遇到那个错误。
int sumAge = personList.stream().mapToInt(Person::age).sum();

-1
不错。你应该提出一个JDK bug(但首先尝试使用最新版本的代码)。但是,这段代码并没有做到你想要做的事情。教程中有一个正确实现的例子:https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html 在你的代码中,result += ... 没有意义,因为它是一个局部参数。而且,我相信编译器很难推断它的类型。
顺便说一下,reduce 只需要两个参数,而你提供了三个。

reduce 可以接受三个参数。您可以在 https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#reducing-U-java.util.function.Function-java.util.function.BinaryOperator- 上进行验证。 - Soumya
@Soumya 但它将第二个参数作为函数,即单个参数lambda,但您正在指定(result, person)。 您在这里究竟想做什么? - kan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接