【问题标题】:Static context cannot access non-static in Collectors静态上下文无法访问收集器中的非静态
【发布时间】:2017-03-03 12:33:38
【问题描述】:

我有一群学生。首先,我想按标记对它们进行分组。然后我想进一步将这些集合分组为同名学生。

Map<Integer,Map<String,List<String>>> groupping = students.stream()
                                                    .collect(Collectors.groupingBy(Student::getMarks, 
                                                            Collectors.mapping(Student::getName,Collectors.toList())));

我收到一条错误消息,

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

是的。我非常清楚如果没有实例,我不能引用非静态方法。但是对于所有这些流操作,我对真正出了什么问题感到有些困惑。

而不是如何解决这个问题;我真的很想知道这里发生了什么。感谢您的任何意见!

因为如果我写下面的分组是完全有效的;

Map<Integer,List<Student>> m = students.stream().
        collect(Collectors.groupingBy(Student::getMarks));

这是我的 Student.java 类(如果你需要的话)

public class Student {
    private String name;
    private int marks;
    // getters, setters, constructor and toString
}

【问题讨论】:

  • 你试图在 Map> 中存储什么?我的意思是您要存储在 List 中的 String 对象是什么?学生姓名列表??
  • @SupunWijerathne 实际上,我的意图是将Students 存储在最里面的List
  • 所以它应该是一个List。不是吗? :))

标签: java java-8 java-stream method-reference collect


【解决方案1】:

我认为 Holger 已经对错误给出了很好的解释,以及为什么它一次运行没有多大意义。

考虑到您的目标,我认为这是您需要的解决方案。

 Map<Integer, Map<String, List<Student>>> grouping = students.stream().collect(Collectors.groupingBy(Student::getMarks,
                Collectors.groupingBy(Student::getName)));

这只会为您提供一个学生列表,首先按分数分组,然后按姓名分组。 :))

【讨论】:

  • 如果我们有这个:Map&lt;FavoriteBookEnum , Map&lt;School, List&lt;Student&gt;&gt;&gt; 而不是Map&lt;Integer, Map&lt;String, List&lt;Student&gt;&gt;&gt;,你会怎么做? FavoriteBookEnumStudentSchool 中的一个枚举,只是一个包含一些学校信息的类。我正在尝试获取按最喜欢的书籍分组的地图,但是......没有到达任何地方。
  • 供将来参考或有类似情况的任何人使用 -> stackoverflow.com/questions/63837641/… 刚刚添加了一个关于它的问题。
【解决方案2】:

很遗憾,错误消息“无法从静态上下文引用非静态方法。”当涉及方法引用时,它只是任何类型不匹配问题的占位符。编译器根本无法确定实际问题。

在您的代码中,目标类型 Map&lt;Integer, Map&lt;String, List&lt;String&gt;&gt;&gt; 与组合收集器的结果类型 Map&lt;Integer, List&lt;String&gt;&gt; 不匹配,但编译器并未尝试确定此(独立)结果类型,因为包含方法引用的(嵌套)泛型方法调用需要目标类型来解析方法引用。所以它不会报告分配的类型不匹配,而是解决方法引用的问题。

正确的代码就是

Map<Integer, List<String>> groupping = students.stream()
    .collect(Collectors.groupingBy(Student::getMarks, 
             Collectors.mapping(Student::getName, Collectors.toList())));

【讨论】:

  • 我没有明白你所说的组合收集器的结果类型是什么意思。那是什么?
  • 组合收集器是groupingBy(Student::getMarks, mapping(Student::getName, toList())),如果我们将其视为独立表达式(就像Java 8 之前的所有表达式一样),它将具有结果类型。如果规则是这样,编译器会报简单的Map&lt;Integer, List&lt;String&gt;&gt; cannot be assigned to Map&lt;Integer,Map&lt;String,List&lt;String&gt;&gt;&gt; 错误信息。
  • 不幸的是,Java 8 规则不再那么简单了。对于所谓的“多边形表达式”,目标类型决定了结果类型,因此您可以将groupping 声明为Map&lt;Object,List&lt;CharSequence&gt;&gt; 而不会出现任何错误。这将改进方法引用的函数类型,例如Student::getMarks 将是 Function&lt;Student,Object&gt;Student::getName 将是 Function&lt;Student,CharSequence&gt; 然后。奇怪的错误消息源于尝试为错误的目标类型找到合适的方法。
  • Collectors.mapping返回Map。它在将元素传递给另一个收集器之前映射元素,因此它在将Students 映射到名称Strings 之前将它们传递给Collectors.toList(),然后返回List&lt;String&gt;(而不是List&lt;Student&gt; 就像没有映射一样)。也许the documentation 有帮助。
  • @Naman 我想,它变得更好了,但还有很长的路要走。问题是有一个关于正确程序行为的正式规范和一个关于如何(有效)解析正确程序的解析器理论,但处理错误输入似乎充其量只是一个次要主题。令人惊讶的是,诸如不匹配的括号或错误的分隔符之类的简单错误如何使编译器发疯,尽管这些问题应该很容易发现。但这不是编译器的工作方式……
猜你喜欢
  • 2015-10-21
  • 2011-11-03
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-11
  • 1970-01-01
相关资源
最近更新 更多