Java 9中Stream API的增强

2023/06/09

1. 概述

在这篇简短的文章中,我们重点关注Java 9中对Stream API的加强。

2. Takewhile/Dropwhile

关于这些方法的讨论在StackOverflow上反复出现(最流行的是这个)。

想象一下,我们想通过在前一个Stream的值上添加一个字符来生成一个String的流,直到这个Stream中的当前值的长度小于10。

我们如何在Java 8中解决它?我们可以使用一个短路中间操作,例如limitallMatch,但它们实际上用于其他目的;或者基于Spliterator编写我们自己的takeWhile实现,但这反过来又使这样一个简单的问题复杂化。

如果使用Java 9,解决方案很简单:

return Stream.iterate("", s -> s + "s")
    .takeWhile(s -> s.length() < 10);

takeWhile操作接受一个Predicate,该Predicate应用于元素以确定这些元素的最长前缀(如果流是有序的)或流元素的子集(如果流是无序的)。

为了更好的说明,我们最好理解术语“最长前缀”和“流的子集”的含义:

  • 最长前缀是与给定谓词匹配的流元素的连续序列,序列的第一个元素是这个流的第一个元素,紧跟在序列最后一个元素之后的元素与给定的谓词不匹配。
  • 流的子集是Stream的一些(但不是全部)元素与给定谓词匹配的集合。

理解了这些关键术语后,我们就可以引入另一个新的dropWhile操作了。

它与takeWhile正好相反;如果流是有序的,则dropWile在删除与给定谓词匹配的元素的最长前缀后,会返回由该Stream的剩余元素组成的流。

否则,如果流是无序的,则dropWile在删除与给定谓词匹配的元素子集后返回由该Stream的剩余元素组成的流。

让我们使用前面获得的Stream丢弃前五个元素:

stream.dropWhile(s -> !s.contains("sssss"));

简单地说,对于元素的给定谓词返回true,dropWhile操作将删除元素,并在第一个谓词为false时停止删除。

3. 流迭代

下一个新特性是用于有限流生成的重载迭代方法,不要与返回由某个函数产生的无限顺序有序流的finite变体混淆。

新的迭代通过添加应用于元素的谓词来稍微修改此方法,以确定Stream何时必须终止。它的用法非常方便简洁:

Stream.iterate(0, i -> i < 10, i -> i + 1)
  .forEach(System.out::println);

它可以与相应的for语句相关联:

for (int i = 0; i < 10; ++i) {
    System.out.println(i);
}

4. StreamOfnullable

在某些情况下,我们需要将元素放入Stream中。有时,这个元素可能为null,但我们不希望Stream包含这样的值。它导致编写if语句或三元运算符来检查元素是否为空。

假设collection和map变量已经创建并填充成功,看以下例子:

collection.stream()
  .flatMap(s -> {
      Integer temp = map.get(s);
      return temp != null ? Stream.of(temp) : Stream.empty();
  })
  .collect(Collectors.toList());

为了避免这种样板代码,Java 9已将ofNullable方法添加到Stream类中。通过这种方法,前面的例子可以简单地转换为:

collection.stream()
  .flatMap(s -> Stream.ofNullable(map.get(s)))
  .collect(Collectors.toList());

5. 总结

我们概括了Java 9中Stream API的重大变化,以及这些改进将如何帮助我们以更少的工作量编写更为突出的程序。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章