从01开始 从01开始
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)

peterjxl

人生如逆旅,我亦是行人
首页
  • 计算机科学导论
  • 数字电路
  • 计算机组成原理

    • 计算机组成原理-北大网课
  • 操作系统
  • Linux
  • Docker
  • 计算机网络
  • 计算机常识
  • Git
  • JavaSE
  • Java高级
  • JavaEE

    • Ant
    • Maven
    • Log4j
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • Servlet
  • Spring
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC
  • SpringBoot
  • 学习网课的心得
  • 输入法
  • 节假日TodoList
  • 其他
  • 关于本站
  • 网站日记
  • 友人帐
  • 如何搭建一个博客
GitHub (opens new window)
  • JavaSE

    • 我的Java学习路线
    • 安装Java
    • Java数据类型

    • Java多版本配置
    • 面向对象

    • Java核心类

    • IO

    • Java与时间

    • 异常处理

    • 哈希和加密算法

    • Java8新特性

      • 函数式编程与Lambda
      • Stream介绍
        • 什么是Stream
        • 在编程中使用Stream
        • Stream的本质:计算规则
        • 小结
      • 创建Stream
      • 操作Stream
      • Optional
    • 网络编程

    • Java
  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java并发

  • Java源码

  • JVM

  • 韩顺平

  • Java
  • Java
  • JavaSE
  • Java8新特性
2023-03-13
目录

Stream介绍

# 10.Stream介绍

Java从8开始,不但引入了Lambda表达式,还引入了一个全新的流式API:Stream API。它位于java.util.stream​包中。

声明:本文主要参考廖雪峰老师的教程使用Stream (opens new window),并自己动手实践了一遍。

‍

# 什么是Stream

重点:这个Stream​不同于java.io​的InputStream​和OutputStream​,它代表的是任意Java对象的序列。两者对比如下:

java.io java.util.stream
存储 顺序读写的byte​或char​ 顺序输出的任意Java对象实例
用途 序列化至文件或网络 内存计算/业务逻辑

‍

‍

有同学会问:一个顺序输出的Java对象序列,不就是一个List​容器吗?

再次划重点:这个Stream​和List​也不一样,List​存储的每个元素都是已经存储在内存中的某个Java对象,而Stream​输出的元素可能并没有预先存储在内存中,而是实时计算出来的。

换句话说,List​的用途是操作一组已存在的Java对象,而Stream​实现的是惰性计算,用到的时候再计算。两者对比如下:

java.util.List java.util.stream
元素 已分配并存储在内存 可能未分配,实时计算
用途 操作一组已存在的Java对象 惰性计算

​Stream​看上去有点不好理解,但我们举个例子就明白了

List就好比自助餐,东西都已经做好了,想吃什么就直接去拿就可以

stream就好比普通的饭店,先点菜后再做饭,做好了才可以吃

‍

‍

# 在编程中使用Stream

我们来动手实践下,例如我们要表示一个全体自然数的集合,显然,用List​是不可能写出来的,因为自然数是无限的,内存再大也没法放到List​中。

但是,用Stream​可以做到。写法如下:

Stream<BigInteger> naturals = createNaturalStream(); // 全体自然数
1

我们先不考虑createNaturalStream()​这个方法是如何实现的,我们看看如何使用这个Stream​。

首先,我们可以对每个自然数做一个平方,这样我们就把这个Stream​​转换成了另一个Stream​​:

Stream<BigInteger> naturals = createNaturalStream(); // 全体自然数
Stream<BigInteger> streamNxN = naturals.map(n -> n.multiply(n)); // 全体自然数的平方
1
2

因为这个streamNxN​也有无限多个元素,要打印它,必须首先把无限多个元素变成有限个元素,可以用limit()​方法截取前100个元素,最后用forEach()​处理每个元素,这样,我们就打印出了前100个自然数的平方:

Stream<BigInteger> naturals = createNaturalStream();
naturals.map(n -> n.multiply(n)) // 1, 4, 9, 16, 25...
        .limit(100)
        .forEach(System.out::println);
1
2
3
4

我们总结一下Stream​​的特点:它可以“存储”有限个或无限个元素。这里的存储打了个引号,是因为元素有可能已经全部存储在内存中,也有可能是根据需要实时计算出来的。

‍

# Stream的本质:计算规则

Stream可以理解为只存储了计算规则,需要输出元素的时候,才进行计算。

​Stream​的另一个特点是,一个Stream​可以轻易地转换为另一个Stream​,而不是修改原Stream​本身。

最后,真正的计算通常发生在最后结果的获取,也就是惰性计算。

Stream<BigInteger> naturals = createNaturalStream(); // 不计算
Stream<BigInteger> s2 = naturals.map(BigInteger::multiply); // 不计算
Stream<BigInteger> s3 = s2.limit(100); // 不计算
s3.forEach(System.out::println); // 计算
1
2
3
4

惰性计算的特点是:一个Stream​转换为另一个Stream​时,实际上只存储了计算规则,并没有任何计算发生。

例如,创建一个全体自然数的Stream​,不会进行计算,把它转换为上述s2​这个Stream​,也不会进行计算。再把s2​这个无限Stream​转换为s3​这个有限的Stream​,也不会进行计算。只有最后,调用forEach​确实需要Stream​输出的元素时,才进行计算。我们通常把Stream​的操作写成链式操作,代码更简洁:

createNaturalStream()
    .map(BigInteger::multiply)
    .limit(100)
    .forEach(System.out::println);
1
2
3
4

因此,Stream API的基本用法就是:创建一个Stream​,然后做若干次转换,最后调用一个求值方法获取真正计算的结果:

int result = createNaturalStream() // 创建Stream
             .filter(n -> n % 2 == 0) // 任意个转换
             .map(n -> n * n) // 任意个转换
             .limit(100) // 任意个转换
             .sum(); // 最终计算结果
1
2
3
4
5

‍

# 小结

Stream API的特点是:

  • Stream API提供了一套新的流式处理的抽象序列;
  • Stream API支持函数式编程和链式操作;
  • Stream可以表示无限序列,并且大多数情况下是惰性求值的。
在GitHub上编辑此页 (opens new window)
上次更新: 2023/3/13 09:16:59
函数式编程与Lambda
创建Stream

← 函数式编程与Lambda 创建Stream→

Theme by Vdoing | Copyright © 2022-2023 粤ICP备2022067627号-1 粤公网安备 44011302003646号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式