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

Posted

技术标签:

【中文标题】不能从 java 8 流中的静态上下文引用非静态方法【英文标题】:Non-static method cannot be referenced from a static context in java 8 streams 【发布时间】:2017-07-01 06:08:14 【问题描述】:

我在玩 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)

【问题讨论】:

我收到了与javac 截然不同的信息(更清晰)。尽管在使用方法引用/lambdas 时,我在 Eclipse 中也遇到过类似的错误消息。 请提供 Java 编译器的确切品牌和版本,因为类型推断是经常变化的事情之一。 查看编辑部分了解详情。我正在运行 Intellij Idea 2016.3 注意类似的消息here。 @JornVernee,你能举个例子来说明 Eclipse 中的错误消息吗?对于这个例子,Eclipse (head) 说:“类型不匹配:无法从 Map> 转换为 Map>”,这对我来说非常好。 【参考方案1】:

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

由于在 IntelliJ IDEA 中实现了方法引用解析,错误消息具有误导性。只有当相应的 SAM(单个抽象方法)参数的数量等于方法参数的数量加上一个 并且 第一个 SAM 参数类型与包含类的方法兼容时,它才认为非静态方法引用被解析。请参阅the implementation(也见上面的isSecondSearchPossible 方法,对可变参数方法执行了一些额外的魔法)。

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

我认为这是一个错误,或者至少是一个可用性问题。我刚刚根据similar question 记录了here。希望我们能解决它。

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

更新:已在 IDEA 2017.2 中修复。

【讨论】:

如果它不同意javac,那就是一个错误。 @EJP,它同意程序不正确,但错误信息不同。 Java 语言规范指定了什么是正确的程序,但没有具体说明错误消息应如何查找不正确的程序。请注意,Eclipse 编译器中的错误消息也有所不同,在这种情况下实际上甚至比 javac 消息更好,因为您可以更容易地发现实际错误。您会认为这是 Eclipse 编译器中的错误吗? :-) 对我来说,“非静态和静态引用”与“泛型类型不匹配”的问题相去甚远。 IDEA 的最新版本仍然存在相同的问题,至少对于 map-reduce 错误消息。用 2018.3.6 和 2019.2 测试

以上是关于不能从 java 8 流中的静态上下文引用非静态方法的主要内容,如果未能解决你的问题,请参考以下文章

java ,为啥无法从静态上下文中引用非静态方法

无法从静态上下文中引用非静态 变量 this

不能从静态上下文中引用非静态变量 x

Java非静态变量引用错误?

如何在ios framework中引用其他静态库

无法从静态上下文引用非静态方法