Java Streams 特性探索,那些你可能还不知道的隐秘武器

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() 生成无限流,我们应该有一些终止条件,如 limitfindFirstfindAny 等,以避免无限循环。

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,原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

国通快递驿站

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值