1. Stream API概述

前置知识:


Stream API 是Java8的一大亮点,是对集合(Collection)对象的极大增强。它专注于对集合对象进行各种非常便利、高效的聚合操作。或者大批量数据操作。Stream API借助于同样新提供的Lambda表达式,极大提高了编程效率和程序可读性。同时它提供了串行和并行两种模式进行聚合操作。并发模式能更充分的利用到多核处理器的优势,使用fork/join并行方法来拆分任务和加速处理过程。
通常编写并行代码很难,容易出错,但是使用Stream API无须编写一行多线程的代码就可以很方便的写出高性能的并发程序。所以说,Java8 中的 java.util.stream是一个函数式语言与多核时代综合影响下的产物。

什么是聚合操作

在传统Java应用中,Java代码经常不得不依赖于关系型数据库的聚合操作来完成诸如以下的事项:

  • 客户每月平均消费金额
  • 最昂贵的在售商品
  • 取10个数据样本作为首页推荐
    在Java的集合API中,仅仅有极少量的辅助性方法,更多时候是用Iterator来遍历集合,完成相关聚合应用逻辑。这是一种远不够高效、笨拙的方法。

什么是Stream

Stream不是集合元素,它不是数据结构,并不能保存数据,而是有关算法和计算的,更像一个高级版本的Iterator。
Stream如同一个迭代器Iterator,单向,不可往复,数据只能遍历一次,遍历一次过后就用尽了。
和迭代器不同的是,Stream可以并行化操作,迭代器只能命令式地串行化操作。使用并行化去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出,Stream的并行操作以来Java7中引入的Fork/Join框架进行拆分任务和加速处理过程。
Stream的另一大特点是数据源本身可以是无限的。

Stream的构成

当我们使用一个Stream时,通常包括3个基本步骤:

  • 获取一个数据源
  • 数据转换
  • 执行操作获取想要的结果
    每次转换原有的Stream对象不改变,返回一个新的Stream对象,这就允许对其操作可以像链条一样排列,变成一个管道

有多种生成Stream数据源的方式:

  • 从Collction和数组

    • Collection.stream()
    • Collection.parallelStream()
    • Arrays.stream( T array)
    • Stream.of()
  • 从BufferedReader

    • java.io.BufferedReader.lines()
  • 静态工厂

    • java.util.stream.IntStream.range()
  • 自己构建

    • java.util.Spliterator
  • 其他

    • Random.ints() 无限生成int范围的数
    • Bitset.stream()

2. Stream使用

简单实例

public class Test2 {
    public static void main(String[] args) {
        IntStream.range(1, 9).filter( x -> x <= 4).forEach(x -> System.out.print(x + " "));
    }
}

// 输出  
1 2 3 4

Stream常用操作

主要分为两类,一类是中间操作,一类是终止操作。
中间操作会返回一个新的Stream流。
终止操作不会返回一个新的Stream流。

中间操作

map

将一种类型的值映射成一个新值(可以不同类型也可以同类型)。

filter

遍历并筛选出满足条件的元素。

终止操作

forEach()

终止操作,对每个元素进行某个操作

collect(Collectors.toList())

终止操作,将Stream流生成一个List列表,也可以用 Collectors.toSet()生成Set集合。

count

终止操作,用于统计Stream中元素个数。

min

终止操作,挑选最小值

max

终止操作,挑选最大值

reduce

终止操作,从Stream计算一个值,计算条件是reduce参数。

Stream高级操作

过滤

除了filter还有

distinct

该方法可以取出重复值,通过hascode和 equals

切分数据

limit(n)

截断Stream,保留n个元素

skip(n)

跳过n个元素

映射

除了map还有

flatMap

它可以将Stream<String[]> 扁平化为 Stream

Stream-flatMap

查找和匹配

返回bool值

allMatch

判断流中元素是否全部与给定条件匹配

anyMatch

判断流中元素只要有任意一个匹配给定条件即可

noneMatch

流中元素都不能匹配给定条件返回真

findFirst

获取流中匹配的第一个元素

findAny

获取流中匹配到的任意一个元素


3. 收集器

Collector接口

在前面介绍的内容里,我们知道终止操作collect需要接受一个Collector接口类型数据来完成数据收集任务。

Collectors

Collectors是Collector的工厂类,它提供了大量的静态方法,这些方法都是返回了一个Collector收集器。

例程:

public class Test2 {

    public static void main(String[] args) {
        String[] str = {"hello", "world", "!"};
        System.out.println(Stream.of(str).collect(Collectors.joining()));
        // 等价于
        // System.out.println(String.join("", str));
    }
}
最后修改:2020 年 12 月 10 日
如果觉得我的文章对你有用,请随意赞赏