前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java8 Stream api 入门

Java8 Stream api 入门

作者头像
呼延十
发布2019-07-01 16:20:44
6790
发布2019-07-01 16:20:44
举报
文章被收录于专栏:呼延呼延

什么是Stream,为什么需要Stream

Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。

Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。

同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的java.util.stream 是一个函数式语言+多核时代综合影响的产物。

----这段介绍引用自IBM的《Java 8 中的 Streams API 详解》 文章写的非常好,给我很大启发,链接会在文末给出

流的使用过程

使用流的过程分为三个步骤: 1.创建一个流 2.对其进行操作(可以是多个操作) 3.关闭一个流

1.创建流

java8提供了多种构造流的方法

  • Collection
  • 数组
  • BufferedReader
  • 静态工厂
  • 自己构建
  • 其他

创建流的示例代码如下:

代码语言:javascript
复制
    List<String> strList = new ArrayList<>();
    strList.add("HuHanShi");
    strList.add("HuBlanker");
    String[] strings = {"HuHanShi", "HuBlanker"};

    //Collection
    Stream<String> stream = strList.stream();
    stream = strList.parallelStream();

    //数组
    stream = Arrays.stream(strings);
    stream = Stream.of(strings);

    //BufferedReader
    stream = new BufferedReader(new InputStreamReader(System.in)).lines();

    //静态工厂
    IntStream streamInt = IntStream.range(0, 10);

    //自己生成流如果有需要放到最后面说

    //其他:随机生成一个int的流
    streamInt = new Random().ints();
    //其他:按照给定的正则表达式切割字符串后得到一个流
    stream = Pattern.compile(",").splitAsStream("wo,w,wa,a");
    stream.forEach(System.out::println);//输出结果为:wo w wa a
2.操作流

当把数据结构包装成流之后,就要开始对里面的元素进行各种操作了。 流的操作分为两种: Intermediate:这类型的方法不会修改原来的流,而是会返回一个新的流以便后续操作。例如:map,filter,sorted. Terminal:这类型的方法会真正的将流进行遍历,在使用过后,流也将会被“消耗”,无法继续操作。 接下来将对常用的(我看过的)流的操作方法一一举例说明:

map()

对当前的流进行一个操作并将得到的结果包装成一个新的流返回。

代码语言:javascript
复制
//str是个字符串列表,将其转换成大写。
	strList.stream().map(String::toUpperCase).collect(Collectors.toList());

flatMap()

flatMap与map的区别是他会将stream内部的结构扁平化,对每一个值都将其转化为一个流,最后将所有刘扁平化为一个流返回。

代码语言:javascript
复制
    Stream<List<Integer>> moreStream = Stream
        .of(Arrays.asList(1, 8), Arrays.asList(2, 4), Arrays.asList(2, 4, 5, 6));

    moreStream.flatMap(Collection::stream).forEach(System.out::println);

输出结果为:1,8,2,4,2,4,5,6. 而不是:[1,8],[2,4],[2,4,5,6].

filter()

filter 对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream。

代码语言:javascript
复制
	//留下包含“Hu”的字符串
    strList.stream().filter(perStr -> perStr.contains("Hu")).forEach(System.out::print);

forEach()

forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。 forEach是Terminal操作,当遍历完成时,流被消耗无法继续对其进行操作。

错误示例:

代码语言:javascript
复制
	//上面的几个示例中用到了forEach来进行打印操作,所以只举一下错误的例子。
	//!这句话是错误的,当forEach之后无法再进行map操作。
    strList.stream().forEach(System.out::print).map();

peek()

有人要问了,我想对每一个元素进行操作一下但是后续还要用怎么办呢,当然是有办法的,那就是peek()方法。

代码语言:javascript
复制
	//先将strList中的字符串打印一遍之后将其转换为大写。
    strList.stream().peek(System.out::print).map(perStr->perStr.toUpperCase()).collect(Collectors.toList());

reduce()

这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。

代码语言:javascript
复制
    Integer sum  = moreStream.flatMap(Collection::stream).reduce(0,(a,b)->a+b);

这个例子将flatMap中的结果进行了累加操作。 reduce()还可以用与字符串连接,求最大最小值等等。

sorted()

对stream中的值进行排序。

代码语言:javascript
复制
strList.sort(String::compareTo);

相比于数组的排序,stream的排序可以先剔除掉一些不需要排序的值,可以减少无用操作。

接下来将一些原理(类型)差不多的放一起说一哈。

limit()/skip()

取前n个元素/跳过前n个元素。

代码语言:javascript
复制
//对strList先取前两个再扔掉第一个然后打印,结果为:HuBlanker。
strList.stream().limit(2).skip(1).forEach(System.out::print);

findFirst()

取stream得第一个值,值得一提的是返回值为Optional<>. Optional是一个容器,可以包含一个值,使用它可以尽量避免NullPointException。 具体见:java8 Optional 类初体验

代码语言:javascript
复制
    String first = strList.stream().findFirst().get();

min()/max()/distinct()

取最小/最大/无重复值。 min和max操作可以通过reduce方法实现,但是因为经常使用所以单独写了出来。

代码语言:javascript
复制
    Arrays.asList(1,1,2,3,4,5,6).stream().min(Integer::min);
    Arrays.asList(1,1,2,3,4,5,6).stream().min(Integer::max);
    Arrays.asList(1,1,2,3,4,5,6).stream().distinct();

Match类方法

match类方法返回一个boolean值。

  • allMatch:Stream 中全部元素符合传入的 predicate,返回 true
  • anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
  • noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
代码语言:javascript
复制
    numList.stream().noneMatch(a -> a > 0);
    numList.stream().allMatch(a -> a > 0);
    numList.stream().anyMatch(a -> a > 0);
3.关闭一个流(将流转化为其他数据结构)

当我们对一个流进行了足够的操作之后,希望将其转换为数据,List等数据结构方便存储。Stream在转换为其他数据结构的时候也是极其方便的。

代码语言:javascript
复制
    //List
    numList.stream().collect(Collectors.toList());
    //Set
    numList.stream().collect(Collectors.toSet());
    //Array
    numList.stream().toArray();
    //String
    numList.stream().toString();

结束语

stream的基本用法到这里就差不多啦,以后有时间的话将自己使用的一些具体栗子逐渐补充一下,毕竟有栗子我们看起来总是更加容易懂一些。 最后!让我再来引用来自IBM的Stream API 详解中的结束语来结束这篇写了好几天的文章吧。

Stream 的特性可以归纳为:

  • 不是数据结构
  • 它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
  • 它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是从 source 删除那些元素。
  • 所有 Stream 的操作必须以 lambda 表达式为参数
  • 不支持索引访问
  • 你可以请求第一个元素,但无法请求第二个,第三个,或最后一个。不过请参阅下一项。
  • 很容易生成数组或者 List
  • 惰性化
  • 很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
  • Intermediate 操作永远是惰性化的。
  • 并行能力
  • 当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
  • 可以是无限的
  • 集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。
参考文章:

Java 8 中的 Streams API 详解

ChangeLog

2018-03-18 完成

以上皆为个人所思所得,如有错误欢迎评论区指正。

欢迎转载,烦请署名并保留原文链接。


本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是Stream,为什么需要Stream
  • 流的使用过程
    • 1.创建流
      • 2.操作流
        • 3.关闭一个流(将流转化为其他数据结构)
        • 结束语
          • 参考文章:
            • ChangeLog
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档