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

Sar*_*ana 8 java comparable comparator java-8

我正在尝试List按名称对员工进行排序,然后使用Java8 Comparator,我在下面创建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
Run Code Online (Sandbox Code Playgroud)

但是如果我明确指定Type,它就可以工作

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

或者通过创建两个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
Run Code Online (Sandbox Code Playgroud)

我已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);
Run Code Online (Sandbox Code Playgroud)

产量

[alan 19, alan 25, mario 25, mario 30]
Run Code Online (Sandbox Code Playgroud)

Ole*_*.V. 7

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

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

如果你看一下这个答案,它在 的参数中有一个类似的类型声明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]));
Run Code Online (Sandbox Code Playgroud)

  • 你怎么推断?你知道`thenComparing()`应该返回一个`Comparator&lt;String&gt;`(以适应赋值的左侧),因此`comparing()`需要返回`Comparator&lt;String&gt;`,因此`s`需要是一个`String`。编译器没有经过这么多的推理步骤。是的,这是类型推断的限制,但我认为这是故意引入的限制,否则规则会变得太复杂,程序员不会理解它们。这是我最好的猜测。 (2认同)
  • 最大的问题是,通过链式调用的目标类型可能会改变后续调用的可用方法,这实际上用于确定前一个目标类型,即使用 `foo(x).bar(y)`,返回类型`foo(x)` 确定是否以及哪些 `bar(...)` 方法可用,但是将目标类型应用于 `foo(x)` 取决于实际选择的 `bar(...)` 方法。 (2认同)