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教程。