Java Stream sorted
最后修改于 2025 年 5 月 24 日
本文深入探讨了 Java Stream 的 sorted
方法,这是一种用于对流中的元素进行排序的多功能工具。 它使开发人员能够以指定的顺序排列数据,例如数字、字符串或自定义对象,使其成为以函数式编程风格处理集合的重要功能。
sorted 方法是 Java Stream API 中的一个中间操作,它生成一个新的流,其中原始流的元素以定义的顺序排列。 作为一个有状态的操作,它必须处理整个流才能确定正确的顺序,这可能会影响大型数据集的性能。 它支持对实现 Comparable
接口的元素进行自然顺序排序,或者按照提供的 Comparator
定义的自定义顺序进行排序。
基本的 sorted 语法
sorted 方法有两个变体
Stream<T> sorted() Stream<T> sorted(Comparator<? super T> comparator)
第一个变体 sorted
按照元素的自然顺序排列元素,要求这些元素实现 Comparable
接口,例如字符串(按字母顺序排序)或数字(按数值排序)。 如果元素未实现 Comparable
,则会发生运行时异常。
第二个变体 sorted(Comparator)
允许使用提供的 Comparator
进行自定义排序逻辑,从而实现灵活的排序,例如反向排序或按特定对象属性排序。 这使其适用于复杂的排序需求。 这两种变体都返回一个新的流,使原始数据源保持不变,并且针对并行处理进行了优化,但开发人员应注意大型流的内存使用情况,因为该操作具有有状态的性质。
数字的自然排序
使用自然顺序对数字进行排序。
void main() { Stream<Integer> numbers = Stream.of(5, 3, 8, 1, 2, 7, 4, 6); numbers.sorted() .forEach(System.out::println); }
此示例使用整数的自然顺序以升序对整数进行排序。 没有参数的 sorted
方法依赖于元素实现 Comparable
。
反向排序
使用 Comparator.reverseOrder
对元素进行反向排序。
void main() { Stream<String> words = Stream.of("banana", "apple", "pear", "orange"); words.sorted(Comparator.reverseOrder()) .forEach(System.out::println); }
此示例以反向字母顺序对字符串进行排序。 Comparator.reverseOrder
方法返回一个比较器,该比较器强制执行自然顺序的反向。
$ java Main.java pear orange banana apple
自定义对象排序
在下面的示例中,我们将使用 Comparator
对自定义对象进行排序。 这是处理用户定义类型集合时的常见情况,例如按年龄或姓名对人员列表进行排序。
record Person(String firstName, String lastName, String occupation) { } void main() { Stream<Person> people = Stream.of( new Person("John", "Doe", "Engineer"), new Person("Jane", "Smith", "Doctor"), new Person("Alice", "Johnson", "Artist"), new Person("Bob", "Brown", "Engineer"), new Person("Charlie", "Davis", "Teacher"), new Person("Diana", "Wilson", "Artist") ); people.sorted(Comparator.comparing(Person::occupation)) .forEach(p -> System.out.println(p)); }
此示例使用 Comparator
按职业对 Person
对象进行排序。 comparing
方法创建一个比较器,该比较器基于指定的属性比较 Person
对象,在本例中为职业。
$ java Main.java Person[firstName=Alice, lastName=Johnson, occupation=Artist] Person[firstName=Diana, lastName=Wilson, occupation=Artist] Person[firstName=Jane, lastName=Smith, occupation=Doctor] Person[firstName=John, lastName=Doe, occupation=Engineer] Person[firstName=Bob, lastName=Brown, occupation=Engineer] Person[firstName=Charlie, lastName=Davis, occupation=Teacher]
此示例演示如何按出生日期对 Person
对象进行排序。
record Person(String firstName, String lastName, String dob) { public int age() { return Period.between(LocalDate.parse(dob), LocalDate.now()).getYears(); } } void main() { Stream<Person> people = Stream.of( new Person("John", "Doe", "1987-01-01"), new Person("Jane", "Smith", "1990-05-15"), new Person("Alice", "Johnson", "2000-03-20"), new Person("Bob", "Brown", "1995-07-30"), new Person("Charlie", "Davis", "1980-12-10"), new Person("Diana", "Wilson", "2002-11-25") ); people.sorted(Comparator.comparing(Person::dob)) .forEach(p -> System.out.println(p)); }
此示例按出生日期 (dob) 对 Person
对象进行排序。 comparing
方法创建一个比较器,该比较器基于指定的属性比较 Person
对象,在本例中为出生日期。 dob
字段应为 yyyy-MM-dd
格式,以便进行正确的按时间顺序排序。
多个排序标准
在下一个示例中,我们将按多个标准对员工列表进行排序:部门、薪水和姓名。
record Employee(String name, String department, double salary) { } void main() { Stream<Employee> employees = Stream.of( new Employee("Alice", "HR", 75000), new Employee("Bob", "IT", 80000), new Employee("Charlie", "IT", 75000), new Employee("Diana", "HR", 80000) ); employees.sorted(Comparator.comparing(Employee::department) .thenComparing(Employee::salary) .thenComparing(Employee::name)) .forEach(e -> System.out.println( e.department() + " - " + e.salary() + " - " + e.name())); }
此示例首先按部门、然后按薪水、最后按姓名对员工进行排序。 thenComparing
方法允许链接多个比较器。
$ java Main.java HR - 75000.0 - Alice HR - 80000.0 - DianathenComparing IT - 75000.0 - Charlie IT - 80000.0 - Bob
不区分大小写的字符串排序
在下一个示例中,我们将以不区分大小写的方式对字符串进行排序。
void main() { Stream<String> mixedCase = Stream.of("apple", "Banana", "cherry", "Date"); mixedCase.sorted(String.CASE_INSENSITIVE_ORDER) .forEach(System.out::println); }
此示例对字符串进行排序,忽略大小写差异。 String.CASE_INSENSITIVE_ORDER
比较器提供字符串的不区分大小写的比较。
$ java Main.java apple Banana cherry Date
使用空值进行排序
下一个示例演示如何使用 Comparator.nullsFirst
和 Comparator.nullsLast
处理排序中的空值。
void main() { Stream<String> withNulls = Stream.of("banana", null, "apple", null, "cherry"); System.out.println("Nulls first:"); withNulls.sorted(Comparator.nullsFirst(Comparator.naturalOrder())) .forEach(System.out::println); System.out.println("\nNulls last:"); Stream<String> withNulls2 = Stream.of("banana", null, "apple", null, "cherry"); withNulls2.sorted(Comparator.nullsLast(Comparator.naturalOrder())) .forEach(System.out::println); }
此示例演示了如何处理排序中的空值。 nullsFirst
将空值放在非空元素之前,而 nullsLast
将它们放在之后。
$ java Main.java Nulls first: null null apple banana cherry Nulls last: apple banana cherry null null
来源
在本文中,我们探讨了 Java Stream 的 sorted
方法。 它提供了灵活的选项,可以使用自然排序或自定义比较器对流元素进行排序。 理解排序对于 Java 中有效的流处理和数据操作至关重要。
作者
列出所有Java教程。