Java 企业级工具类全家桶-50-集合排序工具类

📌 拿来即用 : Java 企业级工具类全家桶-50-集合排序工具类

📋 目录


一、工具类功能

给业务代码用的集合排序入口:列表按单个字段升/降序、按几个字段依次比较、中文按拼音排,另给两个可直接复用的空值安全比较器,不必再手写 Comparator 样板。

排序原地生效、没有返回值,类本身零第三方依赖(拼音序用 JDK 自带的 Collator)。典型场景是员工先按部门再按薪资、订单按金额倒序、城市与姓名的字典序列表。


二、所需环境

JDK 17或以上


三、方法概览(按需调用)

序号 方法 入参 返回 用途
1 sortAsc(List, Function<T, C>) 待排序列表 + key提取函数 void 按单个字段升序,空值排最前
2 sortDesc(List, Function<T, C>) 待排序列表 + key提取函数 void 按单个字段降序,空值排最后
3 sortMultiAsc(List, Function<T, ?>...) 待排序列表 + 依次比较的key提取函数 void 多字段依次升序,空值按该字段最小参与比较
4 sortMultiDesc(List, Function<T, ?>...) 待排序列表 + 依次比较的key提取函数 void 多字段依次降序,空值落在最后
5 sortChinesePinyinAsc(List, boolean) 待排序列表 + null是否排最前 void 中文按拼音升序,null 位置由参数定
6 sortChinesePinyinDesc(List, boolean) 待排序列表 + null是否排最前 void 中文按拼音降序,null 位置由参数定
7 nullsFirstNatural(Function<T, C>) key提取函数 Comparator 造空值排最前的比较器,交给 list.sort 或 stream 复用
8 nullsLastNatural(Function<T, C>) key提取函数 Comparator 造空值排最后、字段仍按升序的比较器

四、调用示例(直观体验)

调用示例直接复制进 IDE 右键 Run 就能看到调用工具类各方法的输出结果。

java 复制代码
21:00:30.789 [main] INFO -- 「SortUtils 方法1 sortAsc(List<T>, Function<T, C>)」原地升序后薪资 -> [-, null, 5000, 7000, 9000]
21:00:30.792 [main] INFO -- 「SortUtils 方法2 sortDesc(List<T>, Function<T, C>)」原地降序后薪资 -> [9000, 7000, 5000, null, -]
21:00:30.794 [main] INFO -- 「SortUtils 方法3 sortMultiAsc(List<T>, Function<T, ?>...)」部门与薪资 -> [-, hr/null, sale/5000, tech/7000, tech/9000]
21:00:30.794 [main] INFO -- 「SortUtils 方法4 sortMultiDesc(List<T>, Function<T, ?>...)」部门与薪资 -> [tech/9000, tech/7000, sale/5000, hr/null, -]
21:00:30.830 [main] INFO -- 「SortUtils 方法5 sortChinesePinyinAsc(List<String>, boolean)」拼音升序(null 在前)-> [null, 安康, 北京, 上海, 台湾, 香港]
21:00:30.831 [main] INFO -- 「SortUtils 方法6 sortChinesePinyinDesc(List<String>, boolean)」拼音降序(null 在后)-> [香港, 台湾, 上海, 北京, 安康, null]
21:00:30.832 [main] INFO -- 「SortUtils 方法7 nullsFirstNatural(Function<T, C>)」交给 list.sort 后薪资 -> [-, null, 5000, 7000, 9000]
21:00:30.840 [main] INFO -- 「SortUtils 方法8 nullsLastNatural(Function<T, C>)」交给 stream.sorted 后薪资 -> [5000, 7000, 9000, null, -]
21:00:30.841 [main] ERROR -- 「异常信息获取演示」不可变列表 -> UnsupportedOperationException
21:00:30.841 [main] ERROR -- 「异常信息获取演示」列表为null -> 待排序列表不能为null
21:00:30.842 [main] ERROR -- 「异常信息获取演示」提取函数为空 -> 至少需要一个key提取函数
21:00:30.843 [main] ERROR -- 「异常信息获取演示」同一字段返回类型不一致 -> class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')

进程已结束,退出代码为 0
java 复制代码
package com.example.order.api;

import com.example.common.utils.SortUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 调用示例:整个文件复制进 IDE,右键 Run 就能看效果。
 *
 * <p>排序工具只吃内存里的列表,不依赖外部服务,也不需要 Spring 容器;示例造一份「薪资有 null、
 * 列表里混一个 null 元素」的数据,把 8 个入口各调一遍,空值的落位与多字段依次比较都能直接看出差别。
 * 日志用 Lombok 的 {@code @Slf4j} + SLF4J 占位符,没装 Lombok 就把 {@code log} 换成项目自己的 Logger。
 */
@Slf4j
public class SortUtilsDemo {

    /** 示例用的员工对象,实际换成你自己的;id=4 那行薪资为 null */
    public record Emp(int id, String dept, Integer salary) {
    }

    public static void main(String[] args) {

        // ========== 一、单个字段直接排 ==========

        List<Emp> ascList = emps();
        SortUtils.sortAsc(ascList, Emp::salary);
        log.info("「SortUtils 方法1 sortAsc(List<T>, Function<T, C>)」原地升序后薪资 -> {}", salaries(ascList));

        List<Emp> descList = emps();
        SortUtils.sortDesc(descList, Emp::salary);
        log.info("「SortUtils 方法2 sortDesc(List<T>, Function<T, C>)」原地降序后薪资 -> {}", salaries(descList));

        // ========== 二、多个字段依次比较 ==========

        List<Emp> multiAscList = emps();
        SortUtils.sortMultiAsc(multiAscList, Emp::dept, Emp::salary);
        log.info("「SortUtils 方法3 sortMultiAsc(List<T>, Function<T, ?>...)」部门与薪资 -> {}", deptSalary(multiAscList));

        List<Emp> multiDescList = emps();
        SortUtils.sortMultiDesc(multiDescList, Emp::dept, Emp::salary);
        log.info("「SortUtils 方法4 sortMultiDesc(List<T>, Function<T, ?>...)」部门与薪资 -> {}", deptSalary(multiDescList));

        // ========== 三、中文拼音排序 ==========

        List<String> cityAsc = cities();
        SortUtils.sortChinesePinyinAsc(cityAsc, true);
        log.info("「SortUtils 方法5 sortChinesePinyinAsc(List<String>, boolean)」拼音升序(null 在前)-> {}", cityAsc);

        List<String> cityDesc = cities();
        SortUtils.sortChinesePinyinDesc(cityDesc, false);
        log.info("「SortUtils 方法6 sortChinesePinyinDesc(List<String>, boolean)」拼音降序(null 在后)-> {}", cityDesc);

        // ========== 四、比较器工厂复用 ==========

        List<Emp> sortedByComparator = emps();
        sortedByComparator.sort(SortUtils.nullsFirstNatural(Emp::salary));
        log.info("「SortUtils 方法7 nullsFirstNatural(Function<T, C>)」交给 list.sort 后薪资 -> {}",
                salaries(sortedByComparator));

        List<String> streamSalaries = emps().stream()
                .sorted(SortUtils.nullsLastNatural(Emp::salary))
                .map(emp -> emp == null ? "-" : String.valueOf(emp.salary()))
                .toList();
        log.info("「SortUtils 方法8 nullsLastNatural(Function<T, C>)」交给 stream.sorted 后薪资 -> {}", streamSalaries);

        // ========== 五、catch异常信息 ==========

        // 1. 原地排序要求列表可变,List.of 的结果会直接拒绝(它抛的异常不带文案,打异常类型)
        try {
            SortUtils.sortAsc(List.of(new Emp(1, "tech", 9000)), Emp::salary);
        } catch (UnsupportedOperationException e) {
            log.error("「异常信息获取演示」不可变列表 -> {}", e.getClass().getSimpleName());
        }

        // 2. 列表为 null
        try {
            SortUtils.sortAsc(null, Emp::salary);
        } catch (IllegalArgumentException e) {
            log.error("「异常信息获取演示」列表为null -> {}", e.getMessage());
        }

        // 3. 一个提取函数都没传
        try {
            SortUtils.sortMultiAsc(emps());
        } catch (IllegalArgumentException e) {
            log.error("「异常信息获取演示」提取函数为空 -> {}", e.getMessage());
        }

        // 4. 同一字段一会儿给字符串一会儿给数字,比较时由 compareTo 抛类型异常
        try {
            List<Emp> mixed = emps();
            SortUtils.sortMultiAsc(mixed, emp -> emp.id() % 2 == 0 ? emp.dept() : emp.salary());
        } catch (ClassCastException e) {
            log.error("「异常信息获取演示」同一字段返回类型不一致 -> {}", e.getMessage());
        }
    }

    /** 样例数据:薪资有 null,列表里还混了一个 null 元素,排序时它跟着空值规则落位 */
    private static List<Emp> emps() {
        return new ArrayList<>(Arrays.asList(
                new Emp(1, "tech", 9000),
                new Emp(2, "sale", 5000),
                null,
                new Emp(3, "tech", 7000),
                new Emp(4, "hr", null)));
    }

    private static List<String> cities() {
        return new ArrayList<>(Arrays.asList("北京", "上海", null, "安康", "台湾", "香港"));
    }

    /** 只看薪资,null 元素与 null 薪资都写成 - */
    private static List<String> salaries(List<Emp> list) {
        List<String> out = new ArrayList<>(list.size());
        for (Emp emp : list) {
            out.add(emp == null ? "-" : String.valueOf(emp.salary()));
        }
        return out;
    }

    /** 「部门/薪资」拼成一行,多字段排序的结果一眼能对上 */
    private static List<String> deptSalary(List<Emp> list) {
        List<String> out = new ArrayList<>(list.size());
        for (Emp emp : list) {
            out.add(emp == null ? "-" : emp.dept() + "/" + emp.salary());
        }
        return out;
    }
}

五、工具类源码(可直接复制)

📦 「点击此处可下载 Java企业级工具类全家桶-50-集合排序工具类」 的完整源码,拿来即用。


觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯

相关推荐
AI人工智能+电脑小能手1 天前
Java 企业级工具类全家桶-74-JSON序列化工具类
spring boot·jackson·jdk 17·objectmapper·java工具类·json序列化·dto互转
AI人工智能+电脑小能手2 天前
Java 企业级工具类全家桶-68-HTTP请求工具类
spring boot·网络请求·http请求·resttemplate·jdk 17·java工具类·企业级开发
AI人工智能+电脑小能手1 个月前
大白话说Java设计模式-27-策略模式(源码剖析篇)
java·spring·设计模式·策略模式·源码分析·事务管理·comparator
折哥的程序人生 · 物流技术专研3 个月前
Java 23 种设计模式:从踩坑到精通 | 番外:策略 vs 模板方法 —— 组合与继承的终极对决
java·策略模式·java面试·comparator·模版方法模式·java设计模式·从踩坑到精通
刘大猫.6 个月前
java工具:《List集合按照某个属性值又打大小排序》
comparator·sort·自定义排序·集合排序·降序排列·list排序·list集合排序
假客套1 年前
2025 活体识别+人脸认证工具类【阿里云api,需要先申请试用】
阿里云·人脸识别·活体检测·java工具类
刘大猫.1 年前
遍历集合list工具
java·list·遍历list·遍历集合·集合排序·遍历对象返回匹配·遍历集合返回第一个匹配值
杨树林er2 年前
JavaScript字符排序规则(编码排序、字典排序)
开发语言·javascript·ecmascript·排序算法·字典排序·localecompare·拼音排序
萤火虫的小尾巴3 年前
Linux(CentOS Stream 9) 安装 Java JDK 17 (源码方式安装)【图文详细教程】
java·linux·jdk·centos·jdk 17