Java Stream 中 sorted 自定义排序的深度解析与实战应用

目录

一、sorted 方法的两种形式

二、基础自定义排序实现

1. 使用 Lambda 表达式创建 Comparator

2. 利用 Comparator 静态方法简化代码

三、对象属性排序与复合条件排序

1. 自定义对象按单属性排序

2. 多条件复合排序(thenComparing)

四、null 值安全排序与特殊场景处理

1. 处理元素为 null 的集合

2. 对象属性为 null 的排序

五、高级排序技巧与性能优化

1. 自定义比较逻辑(Comparator 实现类)

2. 基本类型排序优化(避免装箱)

3. 并行流中的排序注意事项

六、实战场景:复杂业务排序案例

1. 电商商品多维排序

2. 日志条目按优先级和时间排序

七、排序核心原理与最佳实践


在 Java 的 Stream API 中,sorted方法是实现集合元素排序的核心操作。默认排序基于元素的自然顺序,但实际开发中常需根据业务规则定制排序逻辑。本文将从基础用法到高级技巧,全面解析如何通过Comparator实现灵活的自定义排序。

一、sorted 方法的两种形式

Java Stream 提供了两种sorted方法重载,对应不同的排序策略:

  1. 无参 sorted ()
    要求元素实现Comparable接口,按自然顺序排序:

    List<Integer> nums = Arrays.asList(3, 1, 4, 2);
    nums.stream().sorted().forEach(System.out::print);  // 输出:1234
    
  2. 带 Comparator 的 sorted (Comparator)
    自定义排序规则,灵活性更高:

    List<String> words = Arrays.asList("banana", "apple", "cherry");
    words.stream()
        .sorted(Comparator.comparingInt(String::length))
        .forEach(System.out::println);  // 按长度排序
    
二、基础自定义排序实现
1. 使用 Lambda 表达式创建 Comparator
// 示例1:按字符串长度降序排序
List<String> sortedByLength = Arrays.asList("dog", "elephant", "cat")
        .stream()
        .sorted((s1, s2) -> s2.length() - s1.length())
        .toList();  // 输出:[elephant, dog, cat]

// 示例2:按绝对值升序排序
List<Integer> sortedByAbs = Arrays.asList(-5, 2, -8, 1)
        .stream()
        .sorted((n1, n2) -> Math.abs(n1) - Math.abs(n2))
        .toList();  // 输出:[1, 2, -5, -8]
2. 利用 Comparator 静态方法简化代码

Java 8 为Comparator提供了丰富的静态工厂方法:

// 按字符串长度排序(推荐写法)
List<String> optimizedSort = words.stream()
        .sorted(Comparator.comparing(String::length))
        .toList();

// 逆序排序
List<String> reversed = words.stream()
        .sorted(Comparator.comparing(String::length).reversed())
        .toList();  // 长度降序
三、对象属性排序与复合条件排序
1. 自定义对象按单属性排序
class Person {
    private String name;
    private int age;
    // 构造器与getter略
    
    @Override public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

List<Person> people = Arrays.asList(
    new Person("Alice", 25),
    new Person("Bob", 20),
    new Person("Charlie", 30)
);

// 按年龄升序排序
List<Person> sortedByAge = people.stream()
        .sorted(Comparator.comparingInt(Person::getAge))
        .toList();  // 输出:Bob, Alice, Charlie
2. 多条件复合排序(thenComparing)
// 先按年龄升序,年龄相同则按名字字母顺序降序
List<Person> complexSort = people.stream()
        .sorted(Comparator.comparingInt(Person::getAge)
                .thenComparing(Person::getName, Comparator.reverseOrder()))
        .toList();
四、null 值安全排序与特殊场景处理
1. 处理元素为 null 的集合
List<String> strings = Arrays.asList("apple", null, "banana", null, "cherry");

// null元素排在最前
List<String> nullsFirst = strings.stream()
        .sorted(Comparator.nullsFirst(Comparator.naturalOrder()))
        .toList();  // 输出:[null, null, apple, banana, cherry]

// null元素排在最后
List<String> nullsLast = strings.stream()
        .sorted(Comparator.nullsLast(Comparator.reverseOrder()))
        .toList();  // 输出:[cherry, banana, apple, null, null]
2. 对象属性为 null 的排序
class Product {
    private String name;
    private Double price;  // 价格可能为null
    // 构造器与getter略
}

List<Product> products = Arrays.asList(
    new Product("Laptop", 1000.0),
    new Product("Headphone", null),
    new Product("Mouse", 50.0)
);

// 按价格排序,null价格排在最后
List<Product> sortedByPrice = products.stream()
        .sorted(Comparator.comparing(Product::getPrice, 
                Comparator.nullsLast(Double::compare)))
        .toList();
五、高级排序技巧与性能优化
1. 自定义比较逻辑(Comparator 实现类)
// 复杂比较器:先按长度,再按首字母ASCII码
class CustomComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        int lenComp = Integer.compare(s1.length(), s2.length());
        return lenComp != 0 ? lenComp : s1.charAt(0) - s2.charAt(0);
    }
}

List<String> result = words.stream()
        .sorted(new CustomComparator())
        .toList();
2. 基本类型排序优化(避免装箱)
List<Integer> numbers = Arrays.asList(5, 3, 8, 1);

// 推荐:使用comparingInt避免Integer装箱
List<Integer> optimized = numbers.stream()
        .sorted(Comparator.comparingInt(Integer::intValue))
        .toList();

// 低效:自动装箱会产生额外开销
List<Integer> inefficient = numbers.stream()
        .sorted((a, b) -> a - b)
        .toList();
3. 并行流中的排序注意事项

并行流排序会触发全局数据重组,可能影响性能:

// 谨慎使用并行排序
List<Integer> parallelResult = numbers.parallelStream()
        .sorted()
        .toList();
六、实战场景:复杂业务排序案例
1. 电商商品多维排序
class Product {
    private String name;
    private double price;
    private int sales;
    private LocalDateTime createTime;
    // 构造器与getter略
}

// 排序规则:
// 1. 销量降序(优先)
// 2. 价格升序
// 3. 新品优先(创建时间近)
List<Product> sortedProducts = products.stream()
        .sorted(Comparator.comparingInt(Product::getSales).reversed()
                .thenComparingDouble(Product::getPrice)
                .thenComparing(Product::getCreateTime, Comparator.reverseOrder()))
        .toList();
2. 日志条目按优先级和时间排序
enum LogLevel { DEBUG, INFO, WARN, ERROR }

class LogEntry {
    private LogLevel level;
    private LocalDateTime timestamp;
    // 构造器与getter略
}

// 自定义日志级别顺序:ERROR > WARN > INFO > DEBUG
List<LogEntry> logs = ...;

List<LogEntry> sortedLogs = logs.stream()
        .sorted(Comparator.comparing(LogEntry::getLevel, 
                Comparator.comparingInt(level -> {
                    switch (level) {
                        case ERROR: return 4;
                        case WARN: return 3;
                        case INFO: return 2;
                        case DEBUG: return 1;
                        default: return 0;
                    }
                }).reversed())
                .thenComparing(LogEntry::getTimestamp))
        .toList();
七、排序核心原理与最佳实践
  1. 排序稳定性
    Java 的sorted采用 TimSort 算法,保证稳定排序(相等元素相对顺序不变),适合多级排序场景。

  2. Comparator 链最佳实践

    • Comparator.comparing代替手动a-b计算
    • 复杂比较器提取为静态常量
    • 基本类型优先使用comparingInt/Long/Double
  3. 性能优化关键点

    • 避免在并行流中进行复杂排序
    • 减少不必要的对象装箱(如int vs Integer
    • 对大型集合考虑先排序再处理
// 推荐写法:
static final Comparator<Person> AGE_NAME_COMPARATOR = 
    Comparator.comparingInt(Person::getAge)
            .thenComparing(Person::getName);

// 使用时直接引用常量
people.stream().sorted(AGE_NAME_COMPARATOR).forEach(...)

通过灵活运用Comparator的各种特性,Java Stream 的sorted方法能满足几乎所有排序需求。从简单的属性排序到复杂的业务规则,合理组合comparingthenComparingnullsFirst/Last等方法,可编写出高效且易维护的排序代码。在实际开发中,建议将常用比较器封装为工具类,以提升代码复用性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潜意识Java

源码一定要私信我,有问题直接问

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值