比较然后比较给出编译错误

comparing and thenComparing gives compile error

我正在尝试使用 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

但如果我明确指定 Type

    Comparator<String> c = Comparator.<String, String> comparing(s -> s.split("\s+")[0])
            .thenComparingInt(s -> Integer.parseInt(s.split("\s+")[1])); //works

或者通过创建两个 Compartor 和链

    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]

Java 需要知道所有变量的类型。在许多 lambda 中,它可以推断类型,但在您的第一个代码片段中,它无法猜测 s 的类型。我认为解决该问题的标准方法是明确声明它:

    Comparator<String> c = Comparator.comparing((String s) -> s.split("\s+")[0])
            .thenComparingInt(s -> Integer.parseInt(s.split("\s+")[1]));

如果您查看 this answer,它在 Comparator.comparing() 的参数中有类似的类型声明。

你的方法,显式给出 comparing() 的类型参数,显然也有效。

对于你的另一种方法,声明两个比较器,我非常有信心在这种情况下 Java 可以从赋值左侧的 String 推断出来,就像在传统的 List <String> = new ArrayList<>();。当您继续在同一个表达式中调用 thenComparing() 时,Java 不再能看出左侧的类型是相关的。有点像 int size = new ArrayList<>().size(); 这也有效:

    Comparator<String> name = Comparator.comparing(s -> s.split("\s+")[0]);
    Comparator<String> c = name.thenComparingInt(s -> Integer.parseInt(s.split("\s+")[1]));