【发布时间】:2016-11-09 04:43:27
【问题描述】:
我正在尝试使用 Java8 Comparator 按名称对员工的 List 进行排序,然后在 Comparator 下方创建,但它给了我一个编译器错误
Type mismatch: cannot convert from Comparator<Object> to <unknown>
Comparator<String> c = Comparator.comparing(s -> s.split("\\s+")[0])
.thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); //compile error
但如果我明确指定类型,它会起作用
Comparator<String> c = Comparator.<String, String> comparing(s -> s.split("\\s+")[0])
.thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); //works
或者通过创建两个Compartors 和链
Comparator<String> name = Comparator.comparing(s -> s.split("\\s+")[0]);
Comparator<String> age = Comparator.comparingInt(s -> Integer.parseInt(s.split("\\s+")[1]));
Comparator<String> cc = name.thenComparing(age); //works
我已经在左侧指定了类型Comparator<String>,但是为什么自动类型推断没有找到正确的类型并期望明确指定。
有人可以澄清一下吗?
这里是代码
String[] arr = { "alan 25", "mario 30", "alan 19", "mario 25" };
Comparator<String> c = Comparator.<String, String> comparing(s -> s.split("\\s+")[0])
.thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1]));
List<String> sorted = Arrays.stream(arr).sorted(c).collect(Collectors.toList());
System.out.println(sorted);
输出
[alan 19, alan 25, mario 25, mario 30]
【问题讨论】:
-
我不是泛型类型推断方面的专家,但我猜这只是“过多的自动推断”。可能它无法确定
comparing()方法的类型,因为它没有任何类型可以“锚定”它,这与链接方法不同,在链接方法中您显式地为comparing()的结果赋予类型。无论如何,我认为编写自己的Comparator并只调用一次split会更具可读性。将代码压缩到尽可能少的行中并没有什么好处。 -
Comparator.comparing((String s) -> s.split("\\s+")[0]).thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1]))有效,但为什么需要这个String,它可以从Comparator<String>推断,这是类型推断的限制吗?顺便说一句,使用java version "1.8.0_60" -
@Holger,我不确定我明白了。如果所有年龄都保证为 2 位数,您的单级比较器会很好地工作,但我相信它会将
[alan 102, alan 25, alan 8]排序为这个顺序,这与期望的相反——我说的对吗? -
@Ole VV:确实,这是所选示例的缺陷,它没有显示没有两位数的数字,但我仍然建议避免重复的
split操作并将其实现为单个比较器,即使它由于数字解析而变得更加复杂。对于较大的列表,首先将所有元素转换为(String,int)类型,对它们进行排序,然后将它们转换回String形式可能会更有效......
标签: java java-8 comparator comparable