不能从 java 8 流中的静态上下文中引用非静态方法

2022-09-01 04:38:16

我正在玩 http://www.concretepage.com/java/jdk-8/java-8-unaryoperator-binaryoperator-example 的例子。

我发现真正令人困惑的是,当我在形成收集器时错误地将错误的类型放入一个泛型中时,java编译器给了我一个非常误导性的信息:

不能从静态上下文中引用非静态方法

我的错误与现实中的静态与实例上下文无关:

Map<String, Map<Integer, Integer>> mapOfStudents = list.stream().collect(Collectors.groupingBy(Student::getClassName,
            Collectors.toMap(Student::getName, Student::getAge)));

我的错误是在通用返回类型中。当我纠正它并把:

Map<String, Map<String, Integer>> 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)

答案 1

首先应该注意的是,该消息不是由java编译器(javac)发出的,而是由IntelliJ IDEA发出的。当您实际启动构建过程时,您可以在“消息构建”窗口中看到javac消息。您在编辑器窗口中看到的是由IDEA本身生成的消息,它们可能会有所不同。

由于在 IntelliJ IDEA 中实现了方法引用解析,因此错误消息具有误导性。仅当相应的 SAM(单个抽象方法)参数数等于方法参数数加 1 并且第一个 SAM 参数类型与包含类的方法兼容时它才会考虑解析非静态方法引用。请参阅实现(也是上面的方法,对 varargs 方法执行了一些额外的魔术)。isSecondSearchPossible

如果您的程序没有错误,它可以正常工作。但是,如果你有一个不匹配的类型,则传递给的泛型参数不能被替换,所以它仍然是 ,并且它的方法 first 参数只是与类型不对应。因此,所谓的“第二次搜索”失败,IDEA认为该方法是从静态上下文中引用的。虽然静态和非静态上下文在这里都不适用,但非静态上下文与您的方法更匹配,至少根据参数的数量,因为方法没有接收任何参数。另一方面,IDEA逻辑是“如果非静态上下文不适用,那么它是一个静态上下文”,因此出现错误消息。FunctiontoMapFunction<T, R>applyTStudentgetName()

我会认为这是一个错误,或者至少是一个可用性问题。我刚刚根据类似的问题在这里记录了它。希望我们能解决这个问题。

免责声明:我是IntelliJ IDEA开发人员。

更新:在 IDEA 2017.2 中修复。


答案 2

推荐