当前位置: 首页 > 新闻动态 > 网络资讯

在Java里如何实现成绩排名功能_Java集合排序实战说明

作者:P粉602998670 浏览: 发布日期:2026-02-02
[导读]:Collections.sort()排序需Student实现Comparable或传Comparator,推荐匿名Comparator;用Double.compare()防精度问题和溢出;null值用nullsLast()处理;Stream.sorted()适合不可变排序;并列名次需遍历打标。
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 范围)。

  • 升序排成绩:把 ba 位置换过来
  • 分数相同时按姓名二次排序:链式调用 thenComparing(Student::getName)
  • 如果 studentsnull 或含 null 元素,sort() 会抛 NullPointerException,得提前过滤或用 Comparator.nullsLast()

Stream.sorted() 做不可变排名

想保留原始列表不变、只生成新排名列表?Stream 是更安全的选择。它天然支持链式操作,也更容易嵌入过滤、映射等逻辑。

示例:取前10名且分数 ≥ 60 的学生

List top10 = students.stream()
    .filter(s -> s.getScore() >= 60)
    .sorted((a, b) -> Double.compare(b.getScore(), a.getScore()))
    .limit(10)
    .collect(Collectors.toList());

注意:sorted() 是中间操作,必须接终端操作(如 collectforEach)才会触发;没写 collect 就以为排好序了,结果是空的 Stream,容易误判。

  • sorted() 底层仍调用 Arrays.sort(),性能和 Collections.sort() 接近,不是懒加载
  • 如果数据量极大(比如十万级),Stream 默认串行,不加 parallel() 不会自动并行,别指望它“自动加速”
  • method reference 写排序器更简洁:sorted(Com

    parator.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 对象里 scoreDouble(包装类)就可能为 null,而 Double.compare(null, x) 直接炸。

安全做法是显式处理 null:用 Comparator.nullsLast()nullsFirst() 包一层

Comparator byScore = 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 名次列对不上。

免责声明:转载请注明出处:http://m.lexweb.cn/news/790738.html

扫一扫高效沟通

多一份参考总有益处

免费领取网站策划SEO优化策划方案

请填写下方表单,我们会尽快与您联系
感谢您的咨询,我们会尽快给您回复!