Comparator.nullsLast 和 Comparator.comparingInt

nim*_*o23 5 java

我有一个比较整数(可以为空)的比较器,所以

我尝试使用Comparator.comparingInt,但它不起作用:

public static final Comparator<Task> sort = 
Comparator.comparingInt(x -> x.getNumber(), 
                        Comparator.nullsLast(null));
Run Code Online (Sandbox Code Playgroud)

我收到编译器错误:

The method comparingInt(ToIntFunction<? super T>) 
in the type Comparator is not applicable for 
the arguments ((<no type> x) -> {}, Comparator.nullsLast(null))
Run Code Online (Sandbox Code Playgroud)

当使用comparing而不是 时comparingInt,它可以工作:

   public static final Comparator<Task> sort = 
   Comparator.comparing(x -> x.getNumber(), 
                       Comparator.nullsLast(null));
Run Code Online (Sandbox Code Playgroud)

但我想知道为什么因为我想比较整数所以compareInt将是正确的选择。

如何Comparator.nullsLast与 ? 结合 使用Comparator.comparingInt

rzw*_*oot 8

    \n
  1. Integer并且int不一样。特别是,任何比较 int 的尝试都无法处理null,而您在这里确实需要,所以它是正确的。使用comparing

  2. \n
  3. 您的第一个代码片段不起作用,因为您将 2 个参数传递给该方法,该方法只需要一个:将给定转换为comparingInt的 lambda 。这不是你使用的方式。TaskintnullsLast

  4. \n
  5. 您的第二个代码片段确实有效,但它做了完全不同的事情:它首先Integer从您的 中提取 an Task,然后使用nullsLast比较器实现排序。这意味着空值将是最后一个,是的,并且所有其他整数将按任意顺序排列。正如我所说,这不是你使用的方式nullsLast

  6. \n
\n\n

这就是你的使用方式nullsLast

\n\n

案例:您的任务列表包含 null 而不是任务:

\n\n

someListOfTasks.sort(Comparator.nullsLast(Comparator.comparing(task::getNumber)));

\n\n

案例:您的任务列表包含一个编号为空的任务:

\n\n

someListOfTasks.sort(Comparator.comparing(task::getNumber, Comparator.nullsLast(Comparator.naturalOrder())));

\n\n

(我想这就是你想要的)

\n\n

案例:您的任务列表包含空值而不是任务,并且某些任务的数字为空:

\n\n

someListOfTasks.sort(Comparator.nullsLast(Comparator.comparing(task::getNumber, Comparator.nullsLast(Comparator.naturalOrder()))));

\n\n

这可能感觉相当冗长,但请注意,一个 null 与另一个 null 没有关系,并且您很可能希望 null 任务条目首先排序,而具有 null 数字的非 null 任务最后排序。您的问题中没有任何内容表明您的列表中有空任务,因此您需要第二个示例。

\n\n

那么这意味着什么呢?

\n\n

Comparator.comparing(valueExtractor, valueComparator)是一般语法。您可以省略该valueComparator部分,在这种情况下您将得到所谓的“自然排序”。对于 Integer,0,1,2,3,4....最明显的是 \xe2\x80\x93。对于随机对象,如果它们实现了Comparable(确实java.lang.Integer如此),那么compareTo您尝试排序的对象的方法就会被实现。

\n\n

请注意,根据定义,自然顺序无法处理 null(毕竟,尝试调用compareTonull 会执行与调用任何 null 引用上的任何实例方法相同的操作:它会抛出NullPointerException)。您可以通过不使用自然顺序而是使用 nullsFirst 或 nullsLast 比较器来“修复”该问题。这些“包装”比较器,因此语法是:

\n\n

Comparator.nullsLast(comparatorToWrap)

\n\n

这意味着:首先,将所有空值排序到最后。然后,要比较所有非空条目,请使用comparatorToWrap。在您发布的代码片段中,您已进入null此处comparatorToWrap。规范nullsLast明确指出:这意味着所有非空值都被视为相等,这意味着,如果对列表进行排序、任意顺序,并且对于映射/集,只有 1 个非空键:无论哪种方式,都不是您想要的。您显然希望具有非空数字的任务根据整数的自然顺序进行排序,即具有数字“1”的任务应该比具有数字“2”的任务排序更高。因此,传入自然顺序比较器:Comparator.nullsLast(Comparator.naturalOrder())\xe2\x80\x93 这意味着:首先将所有空值排序到最后,然后根据此处的自然顺序对其余部分进行排序。

\n\n

然后,您希望将这个概念(“最后排序空值,其余按自然顺序排序”)应用到任务本身,而不是应用到任何task.getNumber()返回值,因此我们首先需要一个 lambda 来提取 (so, Task::getNumberor x -> x.getNumber(); 这些意味着同样的事情),然后我们传入Integer比较器来启动:

\n\n
Comparator<Integer> sortIntegersNaturallyWithNullsLast = Comparator.nullsLast(Comparator.naturalOrder());\n\nFunction<Task, Integer> extractNumber = Task::getNumber;\n\nlistOfTasks.sort(Comparator.comparing(extractNumber, sortIntegersNaturallyWithNullsLast));\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意:另一种选择是让任务具有自然顺序:

\n\n
public class Task implements Comparable<Task> {\n    private Integer number;\n    .. rest of class here ..\n\n    @Override public int compareTo(Task other) {\n        Integer o = other.number;\n        if (number == null && o == null) return 0;\n        if (number != null) return -1;\n        if (o != null) return +1;\n        return number.compareTo(o);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后你就可以用Comparator.naturalOrder(): listOfTasks.sort(Comparator.naturalOrder())

\n