1. 引言

本教程将探讨如何使用Collections.sort()方法对Long值进行排序。Java提供了简单的列表排序方式,但处理Long值时需要理解Java的对象比较机制。

2. 理解Long值的自然顺序

默认情况下,Collections.sort()按元素的自然顺序排序。对于Long这类数值类型,自然顺序就是从小到大排列。 这种方式能无缝工作,因为Long类实现了Comparable接口,定义了内在的排序行为。

例如,用compareTo()方法比较500L和200L:

Long a = 500L;
Long b = 200L;
int result = a.compareTo(b);

// result > 0 因为 500 > 200

当没有显式提供比较器时,Collections.sort()等方法默认使用这种自然顺序。看个基于自然顺序的例子:

List<Long> numbers = new ArrayList<>(Arrays.asList(500L, 200L, 800L));
Collections.sort(numbers);

assertEquals(Arrays.asList(200L, 500L, 800L), numbers);

调用Collections.sort()时,Java内部使用compareTo()方法比较元素。 LongcompareTo()方法工作原理:

  • a < b → 返回负数
  • a == b → 返回零
  • a > b → 返回正数

这种方法简单直接,适用于大多数升序排序场景,比如排列交易金额或按时间顺序排序时间戳。

3. 使用Comparator实现降序排序

如果想反转自然顺序,可以用Comparator.reverseOrder()Long值进行降序排序。这比直接修改比较逻辑更简单粗暴。

看降序排序的例子:

Collections.sort(numbers, Comparator.reverseOrder());

assertEquals(Arrays.asList(800L, 500L, 200L), numbers);

Comparator.reverseOrder()会反转自然比较,确保Long值按降序排列,无需手动实现比较器。

4. 创建自定义比较逻辑

除了升序/降序,我们可能需要更复杂的排序逻辑。比如按降序排列或优先处理特定数字(如偶数优先)就需要自定义规则。

Java的Comparator接口允许明确定义这些规则。**Comparator作为比较元素的蓝图,支持超越自然顺序的灵活排序策略。**

假设要根据Long值与目标值(如400L)的距离排序:

List<Long> numbers = new ArrayList<>(Arrays.asList(500L, 200L, 800L));
long target = 400L;

Collections.sort(numbers, (a, b) -> {
    long distanceA = Math.abs(a - target);
    long distanceB = Math.abs(b - target);
    return Long.compare(distanceA, distanceB);
});

assertEquals(Arrays.asList(500L, 200L, 800L), numbers);

比较器计算每个值与目标的绝对差值,然后比较这些距离。 踩坑注意:这里要用Long.compare()而不是直接减法,避免溢出问题。

5. 多条件比较Long值

某些场景需要基于多个条件排序。比如先按绝对值排序,绝对值相同时再按原始值排序。 这可以通过链式比较器实现:

List<Long> numbers = new ArrayList<>(Arrays.asList(-500L, 200L, -800L, 300L));
Collections.sort(numbers, Comparator.comparingLong(n -> Math.abs((Long) n))
  .thenComparingLong(n -> (Long) n));

assertEquals(Arrays.asList(200L, 300L, -500L, -800L), numbers);

thenComparing()用于添加次要比较条件。 这里先用绝对值比较,绝对值相同时再用原始值打破平局。

这种方法特别适合多规则排序场景,比如先按值排序,再按时间戳或名称排序。

6. 处理Long比较中的null值

默认情况下,Collections.sort()不允许null值,遇到null会抛出NullPointerException要处理null,需要自定义比较器定义null的排序位置。

使用Comparator.nullsFirst()将null放在开头:

List<Long> numbers = new ArrayList<>(Arrays.asList(500L, null, 200L, 800L));
Collections.sort(numbers, Comparator.nullsFirst(Comparator.naturalOrder()));

assertEquals(Arrays.asList(null, 200L, 500L, 800L), numbers);

或者用Comparator.nullsLast()将null放在末尾:

Collections.sort(numbers, Comparator.nullsLast(Comparator.naturalOrder()));

assertEquals(Arrays.asList(200L, 500L, 800L), numbers);

7. 基于自定义对象属性比较Long值

实际开发中,Long值常作为自定义对象的属性。比如Transaction类包含Long类型的金额字段,需要按金额排序交易列表。

看完整示例:

class Transaction {
    private Long amount;

    public Transaction(Long amount) {
        this.amount = amount;
    }

    public Long getAmount() {
        return amount;
    }
}

List<Transaction> transactions = new ArrayList<>();
transactions.add(new Transaction(500L));
transactions.add(new Transaction(200L));
transactions.add(new Transaction(800L));

// 按金额排序交易
Collections.sort(transactions, Comparator.comparingLong(Transaction::getAmount));

assertEquals(Arrays.asList(200L, 500L, 800L), transactions.stream().map(Transaction::getAmount).collect(Collectors.toList()));

使用Comparator.comparingLong()直接按属性字段排序,适用于Long值被包装在对象中的场景。

8. 结论

本文探讨了使用Collections.sort()比较Long值的多种方式,包括:

✅ 自然顺序排序
✅ 降序排序
✅ 自定义比较逻辑
✅ 多条件排序
✅ null值处理
✅ 对象属性排序

这些技术让我们能精确控制Long值的排序逻辑,无论是简单列表还是复杂对象都能轻松应对。实际开发中根据具体需求选择合适方案即可。


原始标题:Comparing Long Values Using Collections.sort() | Baeldung