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()
方法比较元素。 Long
的compareTo()
方法工作原理:
- 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
值的排序逻辑,无论是简单列表还是复杂对象都能轻松应对。实际开发中根据具体需求选择合适方案即可。