171. Java Lambda 表达式 - 比较器处理空值:避免 NullPointerException

37 阅读3分钟

171. Java Lambda 表达式 - 比较器处理空值:避免 NullPointerException

Java 中处理空值是非常重要的,尤其是当你需要对包含空值的集合进行排序时。如果不小心,NullPointerException 可能会在运行时导致程序崩溃。因此,如何处理空值,确保代码健壮且易于维护,是我们在编写比较器时必须考虑的一个问题。

🎯 需求:将空值推到末尾并按自然顺序排序

假设我们有一个整数列表,且希望按照以下规则进行排序:

  • 将所有空值null)推到列表末尾
  • 对于非空值,按自然顺序(升序)排序。

🚀 方法一:手动处理空值

可能会尝试通过编写条件判断来处理空值。这是手动实现的方式,代码如下:

Comparator<Integer> comparator =
        (i1, i2) -> {
            if (i1 == null && i2 != null) {
                return 1;  // null 值在后
            } else if (i1 != null && i2 == null) {
                return -1; // null 值在后
            } else {
                return Integer.compare(i1, i2); // 非空值按自然顺序排序
            }
        };

这段代码通过条件判断来比较两个值:

  • 如果 i1nulli2 不为 null,则返回 1,表示 i1null)排在后面。
  • 如果 i1 不为 nulli2null,则返回 -1,表示 i2null)排在后面。
  • 对于两个非空值,使用 Integer.compare(i1, i2) 按自然顺序比较它们。

问题:虽然这种方法可以工作,但代码的可读性较差,且容易出错。特别是当涉及多个复杂条件时,代码会显得冗长且不易维护。

🚀 方法二:使用 Comparator.nullsLast() 工厂方法

幸运的是,Java 提供了简洁的方式来处理空值排序。Comparator 接口提供了 nullsLast()nullsFirst() 等工厂方法,专门用于处理空值。

通过这些方法,我们可以显著简化代码。

Comparator<Integer> naturalOrder = Comparator.naturalOrder();
Comparator<Integer> naturalOrderNullsLast = Comparator.nullsLast(naturalOrder);

Comparator.nullsLast() 会将空值(null)推到列表末尾,其他非空值按自然顺序排序。

📝 示例:排序字符串列表并将空值推到末尾

List<String> strings = Arrays.asList("one", null, "two", "three", null, null, "four", "five");
Comparator<String> naturalNullsLast = Comparator.nullsLast(Comparator.naturalOrder());
strings.sort(naturalNullsLast);
System.out.println(strings);

输出

[five, four, one, three, two, null, null, null]

解释:

  • Comparator.nullsLast()null 值推到列表的末尾。
  • Comparator.naturalOrder() 是按字典顺序对字符串进行排序。
  • 最终,空值(null)出现在列表的最后,而其他字符串按字母顺序排列。

🛠️ nullsFirst():将空值推到开头

如果你想将空值排到开头,可以使用 Comparator.nullsFirst()

Comparator<String> naturalNullsFirst = Comparator.nullsFirst(Comparator.naturalOrder());
strings.sort(naturalNullsFirst);
System.out.println(strings);

输出

[null, null, null, one, three, two, five, four]

🎯 小结:如何处理空值

  • 使用 Comparator.nullsLast() 可以将空值排到末尾,nullsFirst() 将空值排到开头。
  • 通过 Comparator.naturalOrder()Comparator.nullsLast() 组合,我们可以轻松实现排序,并保证空值的处理不会引发 NullPointerException
  • 这种方式使得代码更简洁,避免了手动判断和冗长的条件语句。

💡 拓展思考

  1. 如果要对列表中的对象(如自定义 User 类)按多个字段排序,并且这些字段可能为空,你会如何设计比较器?
  2. 尝试使用 nullsFirst()nullsLast() 来处理其他数据类型(例如数字或日期)的排序。