Java流式编程笔记

Java流式编程笔记

流是一系列与特定存储机制无关的元素。
流式编程采用 内部迭代 ,这是流式编程的核心特性之一。
流操作的类型有三种:创建流修改流元素中间操作, Intermediate Operations),消费流元素终端操作, Terminal Operations)。最后一种类型通常意味着收集流元素(通常是到集合中)。


一、流创建

可以通过 Stream.of() 很容易地将一组元素转化成为流。


  1. int 类型的范围
    IntStream 类提供了 range() 方法用于生成整型序列的流。
  2. iterate()
    Stream.iterate() 以种子(第一个参数)开头,并将其传给方法(第二个参数)。方法的结果将添加到流,并存储作为第一个参数用于下次调用 iterate(),依次类推。
  3. 流的建造者模式
    在建造者设计模式(也称构造器模式)中,首先创建一个 builder 对象,传递给它多个构造器信息,最后执行“构造”。Stream 库提供了这样的 Builder
  4. Arrays
    Arrays 类中含有一个名为 stream() 的静态方法用于把数组转换成为流。
    stream() 同样可以产生 IntStreamLongStreamDoubleStream
  5. 正则表达式
    Java 8 在 java.util.regex.Pattern 中增加了一个新的方法 splitAsStream()。这个方法可以根据传入的公式将字符序列转化为流。但是有一个限制,输入只能是 CharSequence,因此不能将流作为 splitAsStream() 的参数。

二、中间操作

中间操作用于从一个流中获取对象,并将对象作为另一个流从后端输出,以连接到其他操作。


  1. 跟踪和调试
    peek() 操作的目的是帮助调试。它允许你无修改地查看流中的元素。
  2. 流元素排序
    Randoms.java 中,还有另一种形式的实现:传入一个 Comparator 参数。
    sorted() 预设了一些默认的比较器。当然也可以把 Lambda 函数作为参数传递给 sorted()
  3. 移除元素
  • distinct():在 Randoms.java 类中的 distinct() 可用于消除流中的重复元素。相比创建一个 Set 集合,该方法的工作量要少得多。
  • filter(Predicate):过滤操作会保留与传递进去的过滤器函数计算结果为 true 元素。
  1. 应用函数到元素
  • map(Function):将函数操作应用在输入流的元素中,并将返回值传递到输出流中。
  • mapToInt(ToIntFunction):操作同上,但结果是 IntStream
  • mapToLong(ToLongFunction):操作同上,但结果是 LongStream
  • mapToDouble(ToDoubleFunction):操作同上,但结果是 DoubleStream
  1. map() 中组合流
    flatMap() 做了两件事:将产生流的函数应用在每个元素上(与 map() 所做的相同),然后将每个流都扁平化为元素,因而最终产生的仅仅是元素。
  • flatMap(Function):当 Function 产生流时使用。
  • flatMapToInt(Function):当 Function 产生 IntStream 时使用。
  • flatMapToLong(Function):当 Function 产生 LongStream 时使用。
  • flatMapToDouble(Function):当 Function 产生 DoubleStream 时使用。
  • flatMap() 可以将元素流的流扁平化为一个简单的元素流。或者,我们可以使用 String.split() 生成一个数组,其可以被 Arrays.stream() 转化成为流:
    在这里插入图片描述

三、Optional类

一些标准流操作返回 Optional 对象,因为它们并不能保证预期结果一定存在。包括:

  • findFirst() 返回一个包含第一个元素的 Optional 对象,如果流为空则返回 Optional.empty
  • findAny() 返回包含任意元素的 Optional 对象,如果流为空则返回 Optional.empty
  • max()min() 返回一个包含最大值或者最小值的 Optional 对象,如果流为空则返回 Optional.empty
    reduce() 不再以 identity 形式开头,而是将其返回值包装在 Optional 中。(identity 对象成为其他形式的 reduce() 的默认结果,因此不存在空结果的风险)

对于数字流 IntStreamLongStreamDoubleStreamaverage() 会将结果包装在 Optional 以防止流为空。


  1. 便利函数
    有许多便利函数可以解包 Optional ,这简化了上述“对所包含的对象的检查和执行操作”的过程:
  • ifPresent(Consumer):当值存在时调用 Consumer,否则什么也不做。
  • orElse(otherObject):如果值存在则直接返回,否则生成 otherObject
  • orElseGet(Supplier):如果值存在则直接返回,否则使用 Supplier 函数生成一个可替代对象。
  • orElseThrow(Supplier):如果值存在直接返回,否则使用 Supplier 函数生成一个异常。
  1. 创建 Optional
    当在代码中加入 Optional 时,可以使用下面 3 个静态方法:
  • empty():生成一个空 Optional
  • of(value):将一个非空值包装到 Optional 里。
  • ofNullable(value):针对一个可能为空的值,为空时自动生成 Optional.empty,否则将值包装在 Optional 中。
  1. Optional 对象操作
    当流管道生成了 Optional 对象,下面 3 个方法可使得 Optional 的后续能做更多的操作:
  • filter(Predicate):将 Predicate 应用于 Optional 中的内容并返回结果。当 Optional 不满足 Predicate 时返回空。如果 Optional 为空,则直接返回。
  • map(Function):如果 Optional 不为空,应用 FunctionOptional 中的内容,并返回结果。否则直接返回 Optional.empty。
  • flatMap(Function):同 map(),但是提供的映射函数将结果包装在 Optional 对象中,因此 flatMap() 不会在最后进行任何包装。

以上方法都不适用于数值型 Optional。一般来说,流的 filter() 会在 Predicate 返回 false 时移除流元素。而 Optional.filter() 在失败时不会删除 Optional,而是将其保留下来,并转化为空。

四、终端操作

以下操作将会获取流的最终结果。至此无法再继续往后传递流。可以说,终端操作(Terminal Operations)总是在流管道中所做的最后一件事。


  1. 数组
  • toArray():将流转换成适当类型的数组。
  • toArray(generator):在特殊情况下,生成自定义类型的数组。
  1. 循环
  • forEach(Consumer)常见如 System.out::println 作为 Consumer 函数。
  • forEachOrdered(Consumer): 保证 forEach 按照原始流顺序操作。
  1. 集合
  • collect(Collector):使用 Collector 收集流元素到结果集合中。
  • collect(Supplier, BiConsumer, BiConsumer):同上,第一个参数 Supplier 创建了一个新结果集合,第二个参数 BiConsumer 将下一个元素包含到结果中,第三个参数 BiConsumer 用于将两个值组合起来。
  1. 组合
  • reduce(BinaryOperator):使用 BinaryOperator 来组合所有流中的元素。因为流可能为空,其返回值为 Optional
  • reduce(identity, BinaryOperator):功能同上,但是使用 identity 作为其组合的初始值。因此如果流为空,identity 就是结果。
  • reduce(identity, BiFunction, BinaryOperator):更复杂的使用形式,这里把它包含在内,因为它可以提高效率。通常,我们可以显式地组合 map()reduce() 来更简单的表达它。
  1. 匹配
  • allMatch(Predicate) :如果流的每个元素根据提供的 Predicate 都返回 true 时,结果返回为 true。在第一个 false 时,则停止执行计算。
  • anyMatch(Predicate):如果流中的任意一个元素根据提供的 Predicate 返回 true 时,结果返回为 true。在第一个 false 是停止执行计算。
  • noneMatch(Predicate):如果流的每个元素根据提供的 Predicate 都返回 false 时,结果返回为 true。在第一个 true 时停止执行计算。
  1. 查找
  • findFirst():返回第一个流元素的 Optional,如果流为空返回 Optional.empty
  • findAny():返回含有任意流元素的 Optional,如果流为空返回 Optional.empty
  1. 信息
  • count():流中的元素个数。
  • max(Comparator):根据所传入的 Comparator 所决定的“最大”元素。
  • min(Comparator):根据所传入的 Comparator 所决定的“最小”元素。
  1. 数字流信息
  • average() :求取流元素平均值。
  • max()min():数值流操作无需 Comparator
  • sum():对所有流元素进行求和。
  • summaryStatistics():生成可能有用的数据。目前并不太清楚这个方法存在的必要性,因为我们其实可以用更直接的方法获得需要的数据。

以上笔记中的内容整理自 On Java 8 中文版
GitHub Pages 完整阅读:《On Java 8》中文版
Gitee Pages 完整阅读:《On Java 8》中文版

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值