为什么Comparator.comparing不能使用String::toLowerCase方法引用?

13
我想通过Java8的流将一个字符串数组按反向顺序(忽略大小写)排序,而不修改它,并将其打印出来。但我无法做到。
这是我的尝试:
package experimentations.chapter02;

import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.Collectors;

public class StringStream {

    public static void main(String[] args) {
        sortStrings();
    }

    public static void sortStrings(){
        String[] stringsArray = "The quick brown fox has a dirty ladder".split("\\s+");
        System.out.println(
                Arrays.stream(stringsArray)
                .sorted(Comparator.comparing(String::toLowerCase).reversed())
                .collect(Collectors.toList())
        );
    }

}

这里的问题是String :: toLowerCase在静态方法Comparator.comparing 中无法接受。

与此同时,我设法对数组进行排序,但是对其进行了修改

public static void sortStrings(){
        String[] stringsArray = "The quick brown fox has a dirty ladder".split("\\s+");
        System.out.println(
                Arrays.stream(stringsArray)
                .map(String::toLowerCase)
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList())
        );
}

那么,最简单的解决方法是什么?


我找到了解决方案:.sorted((String e) -> e.toLowerCase)。同时,我已经请求删除这篇帖子,因为现在对我来说似乎非常明显,我本可以在没有提问的情况下找到它... - loloof64
2
你的第一个代码片段编译通过了。你使用的是旧版本的Java 8吗?或者是在Eclipse中编译的吗?你提到的问题已经在129版本中修复了。另请参见https://dev59.com/p3zaa4cB1Zd3GeqPQHNU。 - assylias
2个回答

26

问题在于Java无法推断一些复杂表达式的泛型类型。第一条语句可以正常工作,而第二条语句会导致编译时错误:

Comparator<String> comparator = Comparator.comparing(String::toLowerCase);
Comparator<String> comparator = Comparator.comparing(String::toLowerCase).reversed();

解决这个问题的方法有几种,以下是其中三种:

将中间 比较器 存储在一个变量中:

Comparator<String> comparator = Comparator.comparing(String::toLowerCase);
System.out.println(
            Arrays.stream(stringsArray)
            .sorted(comparator.reversed())
            .collect(Collectors.toList()));

请使用String.CASE_INSENSITIVE_ORDER

System.out.println(
            Arrays.stream(stringsArray)
            .sorted(String.CASE_INSENSITIVE_ORDER.reversed())
            .collect(Collectors.toList()));

添加显式类型参数:

System.out.println(
            Arrays.stream(stringsArray)
            .sorted(Comparator.<String,String>comparing(String::toLowerCase).reversed())
            .collect(Collectors.toList()));

OP发布的第一个代码片段编译正常。 - assylias
Arrays.stream(stringsArray).sorted(Comparator.comparing(String::toLowerCase).reversed()).collect(Collectors.toList()) 在 b132 上可以通过 javac/netbeans 编译。 - assylias
1
@assylias:嗯,它在Oracle的最新JDK8版本发布的Java编译器中无法编译通过。 - nosid
更准确地说,编译的是 System.out.println(Arrays.stream(stringsArray).sorted(Comparator.comparing(String::toLowerCase).re‌​versed()).collect(Collectors.toList())); - assylias
1
@assylias:我不确定为什么会出现编译错误。关于方法引用的规则非常复杂。因此,我创建了一个新问题:https://dev59.com/6n7aa4cB1Zd3GeqPrIJf - nosid
显示剩余4条评论

7
我找到了解决方案:
 .sorted((String e) -> e.toLowerCase) 

我认为这个问题与语法有关。
 .sorted(String::toLowerCase)

这意味着编译器期望将一个对象传递给String的实例方法toLowerCase。因此,我需要创建自己的lambda方法,而不忽略lambda参数(String)的类型,否则编译器仍然无法解析它。


IntelliJ告诉我,你最初尝试的是循环推断,这是被禁止的。现在,我尝试理解什么是循环推断 :) - Arnaud Denoyelle
正如assylias所告诉我的那样,似乎一些IDE尚未真正支持Java8的功能。此外,我在Netbeans中尝试了类似的代码,没有任何问题。 - loloof64

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接