为什么stream sorted()无法推断我的类型?

时间:2016-04-17 00:38:52

标签: java java-stream

我正在阅读this article并尝试对文本文件中的某些单词进行计数,发现我无法对其在文章的列表1 中的显示方式进行反向排序。

我有一些代码可以使用:

public class WordCounter {
    public static final PrintWriter out = new PrintWriter(System.out, true);

    public static void main(String... args) throws IOException {
        //The need to put "", in front of args in the next line is frustrating.
        try (Stream<String> lines = Files.lines(Paths.get("", args))) {
            lines.parallel()
              .map(l -> l.toLowerCase().replaceAll("[^a-z\\s]", "").split("\\s"))
              .flatMap(Arrays::stream)
              .filter(s -> !s.isEmpty())
              .collect(Collectors.groupingBy(
                      Function.identity(), Collectors.counting()))
                // Sort Map<K,V> Entries by their Integer value descending
                .entrySet().parallelStream()
// MY QUESTION IS ABOUT THIS METHOD:
                  .sorted(
                    Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()))
// --------------------------------- //
                  .forEachOrdered(e -> out.printf("%5d\t%s\n", e.getValue(), e.getKey()));
        }
        out.close();
    }
}

所以文章会建议这一行:

.sorted(Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()))

可以写成:

.sorted(Comparator.comparing(Map.Entry::getValue).reversed())

为此,Java编译器抱怨:

  

错误:(46,49)java:无效方法引用非静态方法   无法从静态上下文引用getValue()

两个comparing方法签名具有完全相同的第一个参数和静态范围,但前者有效,而后者则抱怨getValue是非静态的。

我最初的想法是把它写成:

.sorted(Map.Entry.comparingByValue())

编译并运行但未反转。或者作为:

.sorted(Map.Entry.comparingByValue().reversed())

再次无法编译,给出错误消息:

  

错误:(48,62)java:不兼容的类型:java.util.Comparator&lt; java.util.Map.Entry&lt; java.lang.Object,V&gt;&gt;无法转换为java.util.Comparator&lt;? super java.util.Map.Entry&lt; java.lang.String,java.lang.Long&gt;&gt;

好的,那应该是:

.sorted(Map.Entry.<String, Long>comparingByValue().reversed())

哪个有效。

我似乎无法看到如何在我的“可写为”行中为Map.Entry::getValue表单提供类似的泛型类型规范。

1 个答案:

答案 0 :(得分:1)

至于为什么会发生这种情况:虽然类型推断在Java 8中已经突飞猛进,但如果将返回值分配给某些东西,它仍然只会使用返回目标类型。

在Java 7中,我们只能在赋值上下文中使用它(使用=)并且它有点笨拙。在Java 8中,它不那么笨重,我们可以在调用上下文中使用它(作为方法参数传递,将其分配给形式参数)。

所以我理解它的方式,如果方法调用没有在赋值上下文或调用上下文中使用,目标类型推断就会关闭,因为它不再是一个叫做 poly的东西表达15.1218.5.2)。所以JLS说。

简而言之,目标类型推断仅在返回值为:

时才有效
  • 使用=直接分配给变量,如v = foo();
  • 直接传递给方法,如bar(foo())

一旦您将方法调用链接起来,例如v = foo().zap(),它就会停止工作。

取消我的评论:

  

我似乎无法看到如何为Map.Entry::getValue表单提供类似的泛型类型规范。

这将是Map.Entry<String, Long>::getValue