正如我们在Java Streams:流创建中所学到的,流管道由源、零个或多个中间操作和一个终端操作组成。

我们还了解到,streams流是懒惰的;仅当终端操作启动时,才对源数据执行计算。

在本文中,我们将进一步探讨streams流操作。

streams流操作

流操作可以是中间操作,也可以是终端操作。中间操作产生另一个流。同样,终端操作也会产生结果或副作用。

让我们看看Java流提供的一些操作。

过滤流

您可以通过将 predicate (T -> boolean) 传递给 filter 方法来过滤流。过滤器是返回过滤流的中间操作。如果您熟悉SQL,可以将谓词视为 where 子句。

List<Book> javaBooks =                                                                          books.stream().filter(book -> book.getCategory().equals(JAVA)).collect(Collectors.toList());

这里根据类别过滤图书流。谓词函数是一个lambda函数 book->book.getCategory().equals(JAVA) 。

时断时续

假设你需要找到所有价格低于42美元的书。您可以执行以下操作:

List<Book> lessThan42 =                                                              books.stream().filter(book -> book.getPrice() < 42).collect(Collectors.toList());

上述方法的一个问题是,即使对书籍进行了排序,过滤器也会遍历整个列表。我们可以使用 takeWhile as 将流短路:

List<Book> priceLessThan42 =                                                            books.stream().takeWhile(book -> book.getPrice() < 42).collect(Collectors.toList());

takeWhile 是在Java9中引入的。

类似地,您可以使用 dropWhile 删除流中与给定条件匹配的元素。此操作是 takeWhile 的补充。

List<Book> priceGreaterThan42 =                                                            books.stream().dropWhile(book -> book.getPrice() < 42).collect(Collectors.toList());

如果流无序,并且该流的某些(但不是全部)元素与给定谓词匹配,则 takeWhile / dropWhile 操作的行为是不确定的。在这种情况下,它可以返回匹配元素的任何子集,包括空流。

查找流的不同元素

distinct() 方法通过应用 equals() 方法返回由 distinct 元素组成的流。这是一个有状态的中间操作。

List<String> publisher =                                                                    books.stream().map(book -> book.getPublisher()).distinct().collect(Collectors.toList());

有状态操作的问题

如果传递给流操作的函数是有状态的,则流管道结果可能是不确定的或不正确的。有状态操作的结果取决于流管道执行期间可能更改的任何状态。

有状态lambda的一个示例是 map() 的参数:

Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...

这里,如果并行执行映射操作,由于线程调度的差异,相同输入的结果可能会因运行而异。然而,对于无状态lambda表达式,结果总是相同的。

截流

您可以通过对流使用限制操作使流短路来截断流。限制是一个有状态的操作。这是一个非常便宜的顺序流操作。但是,在有序并行流上可能非常昂贵。

books.stream().limit(2).collect(Collectors.toList());

可以使用 skip(n) 操作放弃流的前n个元素。与 limit 类似,在有序并行管道上,这可能是一个非常昂贵的操作。

books.stream().skip(2).collect(Collectors.toList());

映射流

可以使用映射函数将一个流映射到另一个流。

map

我们可以应用 map 函数将一个流转换为另一个流。例如,将 Stream<Book> 映射到作者的 Stream<String> 可以作为 books.Stream().map(Book::getAuthor) 完成。 map 操作的结果是在流的每个元素上应用函数 function (T) -> R 之后的另一个流。

static List<String> mapToAuthors(List<Book> books) {               return books.stream().map(Book::getAuthor).collect(Collectors.toList());
}

传递给映射操作的函数应该是无干扰和无状态的;否则,可能会出现不希望出现的行为,并有可能在将来破坏代码。

FlatMap

flatMap 操作将一对多转换应用于流的元素,并将结果元素展平为新的流。

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

与 map 一样,传递给 flatMap 操作的 mapper 函数应该是无干扰和无状态的。

Set<String> s = Stream.of(set1, set2).flatMap(Set::stream).collect(Collectors.toSet());

map 和 flatMap 操作之间的区别是–map仅应用变换。然而, flatMap 也会使流变平。

static void flatMap() {List<Integer> primeNumbers = Arrays.asList(2, 3, 5, 7, 11, 13);List<Integer> evenNumbers = Arrays.asList(2, 4, 6, 8);List<List<Integer>> evenOrPrime = Arrays.asList(primeNumbers, evenNumbers);List<Integer> numbers =evenOrPrime.stream().flatMap(Collection::stream).collect(Collectors.toList());log.info("Flattened map : {}", numbers);}

上面的示例打印–展平地图:[2,3,5,7,11,13,2,4,6,8]。如您所见,flatMap将List<Integer>流展平为Integer流。

映射到原始流

通过分别调用方法mapToInt、mapToDouble和mapToLong,可以将流<T>映射到专用的基本流IntStream、DoubleStream和LongStream。

static DoubleStream mapToPrice(List<Book> books) {  return books.stream().mapToDouble(Book::getPrice);
}

通过调用boxed as,可以将专用基本流转换回非专用流:

static Stream<Double> box(DoubleStream doubleStream) { return doubleStream.boxed();
}

流的匹配元素

Stream类提供了在流中查找匹配元素的方法。有两种方法。返回布尔值,例如anyMatch。另一个返回可选的,例如findAny。

Any Match

如果找到给定谓词的任何匹配项, anyMatch 方法将返回true。这是一种短路终端操作。对于空流,此操作返回false,并且不计算流。

static boolean hasAnyJavaBook(List<Book> books) {                            return books.stream().anyMatch(book -> book.getCategory().equals(JAVA));
}

All Match

当流的元素与给定谓词匹配时, allMatch 方法返回true。这是一种短路终端操作。对于空流,此操作返回true,并且不计算流。

static boolean hasAllJavaBook(List<Book> books) {                         return books.stream().allMatch(book -> book.getCategory().equals(JAVA));
}

None Match

如果流中没有与给定谓词匹配的元素,则 noneMatch 方法返回true。这是一种短路终端操作。对于空流,此操作返回true,并且不计算流。

static boolean hasNoJavaBook(List<Book> books) {                           return books.stream().noneMatch(book -> book.getCategory().equals(JAVA));
}

查找流的元素

Find Any

findAny 方法返回描述流的任意元素的可选值,如果流为空,则返回空可选值。这是一种短路终端操作。此操作的行为是不确定的;它可以返回流的任何元素。

在并行流的情况下,不确定性行为允许实现最佳性能。

static Optional<Book> findAnyJavaBook(List<Book> books) {                         return books.stream().filter(book -> book.getCategory().equals(JAVA)).findAny();
}

Optional<T>类(java.util.Optional)是一个容器对象,用于表示值T的存在或不存在。如果findAny没有找到任何元素,那么它将返回空的Optional而不是null。

Find First

findFirst 方法返回表示流的第一个元素的可选值,如果流为空,则返回空可选值。如果流没有遇到顺序,则可以返回任何元素。

static Optional<Book> findFirstJavaBook(List<Book> books) {                          return books.stream().filter(book -> book.getCategory().equals(Category.JAVA)).findFirst();
}

在并行流中查找第一个元素是昂贵的。如果您不关心返回哪个元素,我们应该使用findAny。

还原操作

还原操作(也称为折叠)通过重复应用组合操作,获取一系列输入元素并将它们组合成单个结果。流类有一些通用的缩减操作,如reduce()和collect(),还有一些专门的缩减操作,如min()、max()等。

Reduce

reduce方法T reduce(T identity,BinaryOperator<T>累加器)使用基于初始标识值的关联累加器函数(BinaryOperator:T,U->R)对流执行reduce操作。这是一个终端操作。

static double sum() {                                List<Integer> numbers = List.of(1, 2, 3, 4, 5); return numbers.stream().reduce(0, (a, b) -> a + b);
}

或者使用方法引用:

private static double sum() {                             List<Integer> numbers = List.of(1, 2, 3, 4, 5);         return numbers.stream().reduce(0, Integer::sum);
}

如果流为空,则返回标识(初始)值。reduce方法的另一个变体是'Optional<T>reduce(BinaryOperator<T>累加器)'返回Optional<T>(对于空流)。

Min和Max

“减少”操作可用于查找最小值和最大值,如下所示:

List<Integer> numbers = List.of(1,2,3,4,5);                   Optional<Integer> min = numbers.stream().reduce(Integer::min);Optional<Integer> max = numbers.stream().reduce(Integer::max);

总结

流操作可以是中间操作,也可以是终端操作。中间操作产生另一个流。同样,终端操作也会产生结果或副作用。

  • 您可以使用 filter 、 distinct 、 takeWhile 、 dropWhile 、 skip 和 limit 方法对流进行过滤和切片。
  • 可以使用“ map ”和“ flatMap ”方法变换流的元素。 flatMap 操作也会使流变平。
  • 您可以使用 findFirst 和 findAny 方法在流中查找元素。
  • 可以通过对给定谓词使用 allMatch 、 anyMatch 和 anyMatch 方法来匹配流。
  • 您可以使用 reduce 组合流的元素。

Java Streams:流操作及示例相关推荐

  1. Java 文件流操作.,互联网 面试官 如何面试

    写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 一. ...

  2. 深度掌握 Java Stream 流操作,让你的代码高出一个逼格

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream` 的操作符大体上分为两种:`中间操作符`和`终止操 ...

  3. 这个方法可以让你的代码高出一个逼格——掌握 Java Stream 流操作

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream` 的操作符大体上分为两种:`中间操作符`和`终止操 ...

  4. 优雅代码的秘密,只因为我掌握了Java Stream 流操作

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream` 的操作符大体上分为两种:`中间操作符`和`终止操 ...

  5. java io流操作_十个Demo进行讲解Java中IO流的常用操作~

    好久不见的IO流 对IO流的学习,我记得还是初学Java基础的时候,后来找工作过程中经常看到有些招聘信息中写到熟悉IO流,现在想想IO流,真的是一脸懵逼,不说这么多废话了,IO流这次好好整理一下. 说 ...

  6. java io流操作_【Java基础】IO流操作

    一.IO流概念: 输入输出流,也就是可以用来读写数据,以及上传下载数据. 二.分类: 1.从流的对象来分:   1)高端流:所有程序或者内存中的流都称为高端流. 2)低端流:所有外界设备中的流都是低端 ...

  7. Java IO流操作规律

    2019独角兽企业重金招聘Python工程师标准>>> IO流主要负责数据的传输. 划分: 按流向分:输入流,输出流: 按数据分:字节流,字符流 抽象基类: 字节流的抽象基类: In ...

  8. java文件流操作注意

    今天做了一个测试: @Testpublic void fileOut() throws Exception {FileOutputStream out = new FileOutputStream(n ...

  9. dout java_一段关于Java文件流操作的代码问题

    小弟在初学阶段,为什么这段代码写到txt文件中之后是乱码呢.我看参考答案上面也是用的writeInt来写的.向各位高手请教解决之道.还有就是小弟积分少,没多少积分拿来悬赏.谢谢各位大侠了. impor ...

最新文章

  1. 236. Lowest Common Ancestor of a Binary Tree
  2. linux假延迟脚本,linux – 期望脚本期望错过发送字符串延迟问题
  3. 以cisco 3550为例介绍IOS的恢复方法:
  4. 计算机英语阅读路线,高考英语阅读理解真题解析·计算机运用
  5. “约见”面试官系列之常见面试题之第六十九篇之document.ready和onload的区别(建议收藏)
  6. php错误403_phpstudy访问文件报错403/Forbidden解决办法
  7. Swift-EasingAnimation
  8. sammon映射 matlab实现,matlab编写的 32个降维程序
  9. View 5.1 重装上阵(3—用户体验篇)
  10. servlet精华讲解
  11. 拉格朗日插值编程实现
  12. python输出10行带标号的hello、world_Python输出hello world(各行命令详解)
  13. Android之崩溃日志本地存储与远程保存
  14. 马化腾是该全面反思腾讯战略了:吃老本不能让腾讯变得伟大!
  15. 谷歌浏览器屏蔽百度热点搜索
  16. Windows 7下Git SSH 创建Key的步骤(by 星空武哥)
  17. windows通过浏览器远程连接Linux服务器的jupyter
  18. 颜体html标签,颜体楷书笔法32式详解,一定不能错过!(超级干货)
  19. JDK更换IDEA如何修改
  20. 多线程模拟火车站售票并发

热门文章

  1. Prometheus+Node_exporter+Grafana监控(附送保姆级别linux安装攻略)
  2. 利用Fiddler给手机设置代理
  3. 自我介绍——当年毕业生版本
  4. 谷歌(Google): reCaptcha(3.0版本)做网站验证
  5. HBuilder开发WAP2APP增加扫一扫功能
  6. HTML常用鼠标指针样式设置
  7. Excel VBA 插入指定图片到单元格并只适应大小
  8. FZU 2240 Daxia Suneast's problem
  9. 批量提取文件名到excel,详细的提取步骤
  10. 2021秋招-场景题-垃圾评论、垃圾短信、垃圾邮件的检测技术方法