无法从java 8流中的静态上下文引用非静态方法
我正在讨论来自http://www.concretepage.com/java/jdk-8/java-8-unaryoperator-binaryoperator-example的例子。
我发现真正令人困惑的是,当我在形成收集器时错误地将错误的类型放入generics中时,java编译器给了我一个非常误导性的消息:
无法从静态上下文引用非静态方法
我的错误与现实中的静态vs实例上下文无关:
Map<String, Map> mapOfStudents = list.stream().collect(Collectors.groupingBy(Student::getClassName, Collectors.toMap(Student::getName, Student::getAge)));
我的错误在于generics返回类型。 当我纠正它并把:
Map<String, Map> mapOfStudents
一切都恢复正常。
有人能解释这种令人困惑的错误信息背后的原因吗? 我确信这是一个很好的,但我没有抓住它。
编辑:
~$ java -version openjdk version "1.8.0_121" OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-0ubuntu1.16.04.2-b13) OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
首先应该注意,消息不是由java编译器(javac)发出的,而是由IntelliJ IDEA发出的。 实际启动构建过程时,可以在“Messages Build”窗口中看到javac消息。 您在编辑器窗口中看到的是由IDEA自己生成的消息,它们可能有所不同。
由于在IntelliJ IDEA中实现了方法参考分辨率,错误消息具有误导性。 它认为只有当相应的SAM(单个抽象方法)参数的数量等于方法参数的数量加上一个并且第一个SAM参数类型与包含类的方法兼容时,才能解析非静态方法引用。 查看实现 (上面也是isSecondSearchPossible
方法,为varargs方法执行了一些额外的魔术)。
如果您的程序没有错误,它可以正常工作。 但是,如果您的类型不匹配,则传递给toMap
的Function
的generics参数不能被替换,因此它仍然是Function
,并且其apply
方法的第一个参数只是T
,它与Student
类型不对应。 因此,所谓的“第二次搜索”失败,IDEA认为该方法是从静态上下文引用的。 虽然静态和非静态上下文在这里都不适用,但非静态上下文更好地匹配您的方法,至少根据参数的数量,因为getName()
方法不接收任何参数。 另一方面,IDEA逻辑是“如果非静态上下文不适用,则它是静态上下文”,因此是错误消息。
我认为这是一个错误,或者至少是一个可用性问题。 我刚刚根据类似的问题 在这里记录了它。 希望我们能解决它。
免责声明:我是IntelliJ IDEA开发人员。
更新 :已在IDEA 2017.2中修复。
- 显示在intellij中的弹出窗口方法实现中
- 如何删除intelliJ IDEA 10.5中的项目?
- 如何使用IntelliJ IDEA执行mvn命令?
- IntelliJ错误 – 在-source 1.6错误中不支持java:try-with-resources。 即使在项目设置中,也选择了1.7 JDK
- 如何使用Selenium / TestNG java文件中的IntelliJ制作可执行jar文件?
- @Nullable / @NotNull与IntelliJ IDEA,Maven和JSR 305
- 如何在IntelliJ Idea中禁用Gradle守护进程?
- 此语言级别不支持intellijfunction(…)。 我无法编译
- Intellij – 像在Eclipse中一样添加项目依赖项