Stream 流

简介

Java 8 引入了一个全新的 API:Stream API,它可以极大地提高 Java 程序员的编程效率和程序的性能。Stream API 是一个来自于函数式编程的概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

Stream 将要处理的元素集合看作一种流,流在管道中传输,通过管道可以对流进行某些计算和操作,比如筛选、排序、聚合等。 每一次操作都在原数据流的基础上生成一个新的流,这样就可以通过多次操作,将操作结果组合起来,最后得到想要的结果。

Stream API 提供了串行和并行两种模式进行操作,可以大大提高程序的运行效率。

Stream 操作分类

Stream 操作可以分为两种类型:中间操作(Intermediate Operations)和终端操作(Terminal Operations)。

Stream 操作分类

中间操作

一个流后面可以跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射、过滤等操作,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅调用到这类方法,并没有真正开始流的遍历。而是当有终端操作时,才开始执行。

中间操作主要有mapfilterdistinctsortedpeeklimitskipparallelsequential 等。

中间操作又可以分为两种:

  • 无状态操作:数据的处理不依赖于前面的数据,比如 mapfilter 等操作。

  • 有状态操作:数据的处理依赖于前面的数据,比如 sorteddistinct 等操作。

// 转换为大写
List<String> list = Arrays.asList("apple", "banana", "orange", "pear", "strawberry");
List<String> result = list.stream()
        .map(String::toUpperCase)
        .collect(Collectors.toList());
System.out.println(result);
// 输出:[APPLE, BANANA, ORANGE, PEAR, STRAWBERRY]

终端操作

一个流只能有一个终端操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。终端操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个副作用。

终端操作主要有forEachcountcollectreduceminmaxfindFirstanyMatchallMatchnoneMatchtoArray 等。

对于流的终端操作,可以分为两种:

  • 非短路操作:对整个流的所有元素进行处理,比如forEachcountcollectreduce等操作。

  • 短路操作:对流中的前 N 个元素进行处理,比如findFirstlimit 等操作。

// 统计长度大于 5 的元素个数
List<String> list = Arrays.asList("apple", "banana", "orange", "pear", "strawberry");
long count = list.stream()
        .filter(s -> s.length() > 5)
        .count();
System.out.println(count);
// 输出:3

Stream 的特点

Stream 的特点可以归纳为:

  • 不是数据结构,不会保存数据:Stream 是一种从源数据中按照特定规则取数据的方式,而不是一个数据容器。

  • 不支持索引访问:Stream 只能对数据进行一次遍历,遍历过一次后即用尽,就像流水一样只能消费一次。

  • 不会改变源对象:Stream 的操作不会修改源数据对象,而是返回一个持有结果的新 Stream。

  • 自动优化:Stream 会自动进行优化,比如延迟执行(lazy)和短路(short-circuiting)。只有在执行终端操作时,中间操作才会被执行。

  • 链式调用:通过操作管道的方式,可以对操作进行链式调用,使代码更加简洁和易读。

  • 支持并行操作:Stream 的操作可以是串行的,也可以是并行的,通过并行流可以利用多核处理器的优势,提高性能。

最后更新于

这有帮助吗?