Collections.sort()排序需Student实现Comparable或传Comparator,推荐匿名Comparator;用Double.compare()防精度问题和溢出;null值用nullsLast()处理;Stream.sorted()适合不可变排序;并列名次需遍历打标。

用 Collections.sort() 对学生成绩列表排序
直接对 List 排序最常用,前提是 Student 实现 Comparable 或传入 Comparator。别直接改 Student 类去实现 Comparable——万一以后要按姓名、学号、年龄多维度排序,硬编码比较逻辑会失控。
推荐写匿名 Comparator 或方法引用:
Collections.sort(students, (a, b) -> Double.compare(b.getScore(), a.getScore()));
注意:这里用 Double.compare() 而不是 a.getScore() - b.getScore(),避免浮点数减法导致的精度问题或整数溢出(比如分数是 int 但值超出了 Integer.MAX_VALUE - Integer.MIN_VALUE 范围)。
- 升序排成绩:把
b和a位置换过来 - 分数相同时按姓名二次排序:链式调用
thenComparing(Student::getName) - 如果
students是null或含null元素,sort()会抛NullPointerException,得提前过滤或用Comparator.nullsLast()
用 Stream.sorted() 做不可变排名
想保留原始列表不变、只生成新排名列表?Stream 是更安全的选择。它天然支持链式操作,也更容易嵌入过滤、映射等逻辑。
立即学习“Java免费学习笔记(深入)”;
示例:取前10名且分数 ≥ 60 的学生
Listtop10 = students.stream() .filter(s -> s.getScore() >= 60) .sorted((a, b) -> Double.compare(b.getScore(), a.getScore())) .limit(10) .collect(Collectors.toList());
注意:sorted() 是中间操作,必须接终端操作(如 collect、forEach)才会触发;没写 collect 就以为排好序了,结果是空的 Stream,容易误判。
-
sorted()底层仍调用Arrays.sort(),性能和Collections.sort()接近,不是懒加载 - 如果数据量极大(比如十万级),
Stream默认串行,不加parallel()不会自动并行,别指望它“自动加速” - 用
method reference写排序器更简洁:sorted(Comparator.comparingDouble(Student::getScore).reversed())
处理并列排名(同分同名次)的逻辑怎么写
真实成绩单里“95、95、92”应该显示为“1、1、3”,而不是“1、2、3”。Java 集合排序本身不提供这种名次计算,得自己遍历打标。
关键点:不能只依赖排序后索引(i + 1),必须比对相邻分数是否相等:
int rank = 1;
for (int i = 0; i < rankedStudents.size(); i++) {
Student s = rankedStudents.get(i);
if (i > 0 && Double.compare(s.getScore(), rankedStudents.get(i-1).getScore()) == 0) {
s.setRank(rank); // 分数相同,名次不变
} else {
rank = i + 1;
s.setRank(rank);
}
}这里用 Double.compare() 判断相等,而非 ==,防止浮点误差;如果分数字段是 BigDecimal,就得用 compareTo()。
- 别在
sort()里试图塞进名次逻辑——排序器只能返回 -1/0/1,没法传状态 - 如果要输出“1、1、3、4、4、6”这种跳名次(即并列后下一个名次跳过占用位),上面代码已满足;若要“1、1、2、3、3、4”这种连续名次,把
rank = i + 1改成rank++即可 - 并发环境下做排名需额外同步,单线程场景不用加锁
成绩字段为 null 时排序崩溃怎么办
NullPointerException 是最常踩的坑。哪怕数据库字段允许为空,Java 对象里 score 是 Double(包装类)就可能为 null,而 Double.compare(null, x) 直接炸。
安全做法是显式处理 null:用 Comparator.nullsLast() 或 nullsFirst() 包一层
ComparatorbyScore = Comparator.comparing( Student::getScore, Comparator.nullsLast(Comparator.reverseOrder()) );
这样 null 成绩会被排在最后(降序时),且不会抛异常。如果业务要求 null 当作 0 处理,就该在 getScore() 里返回 Objects.requireNonNullElse(score, 0.0),而不是在排序器里硬转——职责要分明。
- 别依赖 IDE 自动生成的
compareTo(比如 Lombok 的@Data),它对null字段默认抛异常 - MyBatis 等 ORM 框架查出的
null值,有时会变成0.0或空字符串,取决于类型处理器,务必实测 - 单元测试一定要覆盖
score = null场景,否则上线后第一份零分名单就崩
排名功能看着简单,真正落地时 null 值、浮点精度、并列规则、原始数据不可变这几个点,漏掉任何一个都可能让导出的 Excel 名次列对不上。










