Java Streams 从一开始就配备了强大的特性,Java 开发者也在不断通过每个版本改进它们。在本文中,我们将探索一些您可能还不知道的隐藏特性。
你可能还不知道但又可能又特别好用的特性/方法
以下我们通过示例来讲解这些方法
Stream.ofNullable:
这个方法在 Java 9 中引入,有助于从集合中过滤所有空值,从而潜在地帮助我们避免空指针异常。
我们可以使用 filter(predicate)
来实现这一点,如下所示:
List<String> results = names.stream()
.flatMap(Stream::ofNullable)
.collect(Collectors.toList());
我们使用了 filter
方法来实现这一点,但显然不够简洁。这就是 Java 9 中 Stream.ofNullable
派上用场的地方,因为它直接处理流中的空值。
List<String> results = names.stream()
.flatMap(Stream::ofNullable)
.collect(Collectors.toList());
Stream.iterate():
iterate()
方法用于创建序列的无限流。
它接受一个种子和一个一元函数,将该函数应用于前一个元素。
由于 iterate()
生成无限流,我们应该有一些终止条件,如 limit
、findFirst
或 findAny
等,以避免无限循环。
Stream.iterate(1, n -> n + 3)
.limit(5)
.forEach(System.out::println);
Collectors.collectingAndThen:
Collectors.collectingAndThen
是一个收集器,允许您在另一个收集器的结果上执行额外的转换。当您希望在返回结果之前对结果应用最终转换或操作时,它非常有用。
List<Employee> employees = Arrays.asList(
new Employee("Alice", 50000),
new Employee("Bob", 65000),
new Employee("Charlie", 78000),
new Employee("Sarah", 45000)
);
// 计算平均工资并四舍五入到最近的整数
int averageSalary1 = employees.stream()
.mapToDouble(Employee::getSalary)
.boxed()
.collect(Collectors.collectingAndThen(
Collectors.averagingDouble(Double::doubleValue), // 第一个收集器:找到平均工资
average -> (int) Math.round(average))); // 额外操作:四舍五入到最近的整数
System.out.println("Average Salary after roundup: " + averageSalary1);
Stream.takeWhile 和 Stream.dropWhile:
takeWhile()
和 dropWhile()
方法在 java9 中引入,用于有条件地处理流。
dropWhile()
从流中丢弃或拒绝元素,直到条件为真。
takeWhile()
考虑或接受流中的元素,直到条件为真。
让我们用一个例子来简化这一点,假设您有一个整数列表如下 [1, 2, 3, 4, 6, 7, 8, 9, 10]:
这里您想从流中取出所有小于 5 的元素,您可以简单地使用 takeWhile()
(在满足条件时取元素)
List<Integer> takeWhileResult = numbers.stream()
.takeWhile(num -> num <= 5)
.collect(Collectors.toList());
// 输出:[1, 2, 3, 4]
好的,我将帮您翻译附件中的文章,并将代码部分以Markdown格式输出。
Java Streams 特性:探索开发者可能还不知道的隐藏方法
Java Streams 从一开始就配备了强大的特性,Java 开发者也在不断通过每个版本改进它们。在本文中,我们将探索一些您可能还不知道的隐藏特性。
列出一些鲜为人知的特性/方法
让我们通过示例详细了解每一种方法。
Stream.ofNullable:
这个方法在 Java 9 中引入,有助于从集合中过滤所有空值,从而潜在地帮助我们避免空指针异常。
我们可以使用 filter(predicate) 来实现这一点,如下所示:
java
List <String>
results1 = names.stream()
.filter(username -> username != null)
.collect(Collectors.toList());
我们使用了 filter 方法来实现这一点,但它有点不够简洁。这就是 Java 9 中 Stream.ofNullable 派上用场的地方,因为它直接处理流中的空值。
java
List <String>
results = names.stream()
.flatMap(Stream::ofNullable)
.collect(Collectors.toList());
Stream.iterate():
iterate() 方法用于创建序列的无限流。
它接受一个种子和一个一元函数,将该函数应用于前一个元素。
java
Stream.iterate(1, n -> n + 3)
.forEach(System.out::println);
由于 iterate() 生成无限流,我们应该有一些终止条件,如 limit、findFirst 或 findAny 等,以避免无限循环。
java
Stream.iterate(1, n -> n + 3)
.limit(5)
.forEach(System.out::println);
此方法将生成算术序列的前 5 个数字,如:1, 4, 7, 10, 13
Collectors.collectingAndThen:
Collectors.collectingAndThen 是一个收集器,允许您在另一个收集器的结果上执行额外的转换。当您希望在返回结果之前对结果应用最终转换或操作时,它非常有用。
java
List <Employee>
employees = Arrays.asList(
new Employee(“Alice”, 50000),
new Employee(“Bob”, 65000),
new Employee(“Charlie”, 78000),
new Employee(“Sarah”, 45000)
);
// 计算平均工资并四舍五入到最近的整数
int averageSalary1 = employees.stream()
.mapToDouble(Employee::getSalary)
.boxed()
.collect(Collectors.collectingAndThen(
Collectors.averagingDouble(Double::doubleValue), // 第一个收集器:找到平均工资
average -> (int) Math.round(average))); // 额外操作:四舍五入到最近的整数
System.out.println("Average Salary after roundup: " + averageSalary1);
Stream.takeWhile 和 Stream.dropWhile:
takeWhile() 和 dropWhile() 方法在 java9 中引入,用于有条件地处理流。
dropWhile() 从流中丢弃或拒绝元素,直到条件为真。
takeWhile() 考虑或接受流中的元素,直到条件为真。
让我们用一个例子来简化这一点,假设您有一个整数列表如下 [1, 2, 3, 4, 6, 7, 8, 9, 10]:
这里您想从流中取出所有小于 5 的元素,您可以简单地使用 takeWhile()(在满足条件时取元素)
java
List <Integer>
takeWhileResult = numbers.stream()
.takeWhile(num -> num <= 5)
.collect(Collectors.toList());
// 输出:[1, 2, 3, 4]
如果您想丢弃小于 5 的元素,那么您可以使用 dropWhile()(在满足条件时丢弃元素)
java
List <Integer>
dropWhileResult = numbers.stream()
.dropWhile(num -> num <= 5)
.collect(Collectors.toList());
// 输出:[6, 7, 8, 9]
下面是一个包括两种方法的例子
/**
在下面的例子中,我们丢弃元素直到它们小于 3,然后我们取直到元素小于 7。简而言之,从 4 到 7 取元素
**/
List<Integer> result = numbers.stream()
.dropWhile(num -> num <= 3)
.takeWhile(num -> num <= 7)
.collect(Collectors.toList());
System.out.println(result);
Collectors.teeing():
Collectors.teeing() 是 Java 12 中引入的收集器。它允许您并行执行两个收集器,然后使用指定的函数组合它们的结果。
List<Integer> integerList = Arrays.asList(12, 19, 38, 397, 16, 980, 37, 165, 587, 87, 987, 568);
Map map = integerList.stream().collect(Collectors.teeing(
Collectors.maxBy(Integer::compareTo),// 第一个收集器:找到最大值
Collectors.minBy(Integer::compareTo),// 第二个收集器:找到最小值
(e1, e2) -> Map.of("max", e1.get(), "min", e2.get()) // 将结果组合在一个映射中
));
System.out.println(map);
Stream.concat():
stream.concat()
方法用于连接两个流,并生成一个新的流。
Stream<Integer> stream1 = Stream.of(1, 2, 3);
Stream<Integer> stream2 = Stream.of(4, 5, 6);
// 将两个流连接成一个流
Stream<Integer> combinedStream = Stream.concat(stream1, stream2);
// 计算所有整数的总和
int sum = combinedStream.mapToInt(Integer::intValue).sum();
System.out.println("Sum: " + sum); // 输出:Sum: 21 (1 + 2 + 3 + 4 + 5 + 6)
Collectors.partitioningBy:
Collectors.partitioningBy
是 Java 8 中引入的收集器,用于根据布尔条件将流中的元素分成两组。它通常用于当您想要将流中的元素分成两类:满足某个条件的元素和不满足该条件的元素。
partitioningBy
收集器接受一个谓词作为参数,定义了分区元素的条件。它返回一个 Map<Boolean, List<T>>
,其中键是 true 和 false,代表基于元素是否满足条件的两组。与每个键相关联的值是包含满足条件(true)或不满足条件(false)的元素的列表。
// 将数字分成偶数和奇数组
Map<Boolean, List<Integer>> partitionedNumbers = numbers.stream()
.collect(Collectors.partitioningBy(num -> num % 2 == 0));
System.out.println(partitionedNumbers);
// 输出分区的数字
System.out.println("Even numbers: " + partitionedNumbers.get(true));
System.out.println("Odd numbers: " + partitionedNumbers.get(false));
示例 2
double thresholdSalary = 60000;
// 根据工资阈值将员工分成两组
Map<Boolean, List<Employee>> partitionedEmployees = employees.stream()
.collect(Collectors.partitioningBy(employee -> employee.getSalary() > thresholdSalary));
// 打印分区的员工
System.out.println("Employees earning more than " + thresholdSalary + ": " + partitionedEmployees.get(true));
System.out.println("Employees earning less than or equal to " + thresholdSalary + ": " + partitionedEmployees.get(false));
IntStream for Ranges
在 Java 8 中,您可以使用 IntStream 创建代表一系列数字范围的整数流。IntStream 接口提供了几种方法来创建这样的流:
range(int startInclusive, int endExclusive):
从 startInclusive 开始创建一个整数流,直到但不包括 endExclusive。
rangeClosed(int startInclusive, int endInclusive):
从 startInclusive 开始创建一个整数流,直到并包括 endInclusive。
List<Integer> intStream1 = IntStream.range(1, 10)
.boxed() // 将 IntStream 转换为 Stream<Integer>
.collect(Collectors.toList());
System.out.println(intStream1);
List<Integer> intStream2 = IntStream.rangeClosed(1, 10)
.boxed() // 将 IntStream 转换为 Stream<Integer>
.collect(Collectors.toList());
System.out.println(intStream2);
小伙伴们,到这里就结束了!如果对您有帮助,不要忘记关注我的博客哟。
以上文章翻译自medium,原文链接