【JDK 8特性】Stream API 详解

乐猿社区,程序员的花果山java

Stream 做为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是彻底不一样的概念。Java 8 中的 Stream 是对集合(Collection)对象功能的加强,它专一于对集合对象进行各类很是便利、高效的聚合操做(aggregate operation),或者大批量数据操做 (bulk data operation)。Stream API 借助于 Lambda 表达式,极大的提升编程效率和程序可读性。程序员

什么是 Stream?

Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就比如流水从面前流过,一去不复返。而和迭代器又不一样的是,Stream 能够并行化操做,迭代器只能命令式地、串行化操做。顾名思义,当使用串行方式去遍历时,每一个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分红多个段,其中每个都在不一样的线程中处理,而后将结果一块儿输出。编程

流的操做类型分为两种:

  • Intermediate:一个流能够后面跟随零个或多个 intermediate 操做。其目的主要是打开流,作出某种程度的数据映射/过滤,而后返回一个新的流,交给下一个操做使用。这类操做都是惰性化的(lazy),就是说,仅仅调用到这类方法,并无真正开始流的遍历。
操做 类型 返回类型 目的
filter 中间操做 Stream<T> 过滤元素
distinct 中间操做 Stream<T> 去掉重复的元素
skip 中间操做 Stream<T> 跳过指定数量的元素
limit 中间操做 Stream<T> 限制元素的数量
map 中间操做 Stream<T> 流的转化
flatmap 中间操做 Stream<T> 流的扁平化
sorted 中间操做 Stream<T> 元素排序

map与flatmap的区别:map是将list转成list,而flatmap是将多个List合并成一个list并发

  • Terminal:一个流只能有一个 terminal 操做,当这个操做执行后,流就被使用“光”了,没法再被操做。因此这一定是流的最后一个操做。Terminal 操做的执行,才会真正开始流的遍历,而且会生成一个结果,或者一个 side effect。
操做 类型 返回类型 目的
forEach 终端操做 void 消费流中的每一个元素,返回void
count 终端操做 R 返回流中元素的个数,返回long
collect 终端操做 Stream<T> 把流归约为一个集合
anyMatch 终端操做 boolean 流中是否有符合要求的元素
noneMatch 终端操做 boolean 流中是否没有任何符合要求的元素
allMatch 终端操做 boolean 流中是否全部元素都是符合要求的
findAny 终端操做 Optional<T> 查找符合要求的元素
findFirst 终端操做 Optional<T> 查找第一个符合要求的元素
reduce 终端操做 Optional<T> 归约

怎样建立流?

Stream 提供两咱建立流的方式dom

  • stream() − 为集合建立串行流。
  • parallelStream() − 为集合建立并行流。

Stream提供串行和并行两种模式进行汇聚操做,并发模式可以充分利用多核处理器的优点,使用 fork/join 并行方式来拆分任务和加速处理过程。stream 是一个函数式语言+多核时代综合影响的产物编程语言

过滤元素 - filter

如下的代码返回不为空的字符串ide

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取不为空的字符串
List<String>  result = strings.stream().filter(string -> string.isEmpty()).collect(Collectors.toList());

筛选重复的元素 - distinct

如下代码会筛选出列表中全部的偶数,并确保没有 重复函数

List<Integer> numbers = Arrays.asList(1,2,1,3,3,2,4);
 //去重元素2
numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);

跳过指定数量的元素 - skip

返回一个扔掉了前n个元素的流。若是流中元素不足n个,则返回一 个空流。limit(n) 和 skip(n) 是互补的。线程

//去掉符合要求的集合中的前2个元素后返回
List<User> dishSkip = userList.stream()
        .filter(d -> d.getAge() > 20).skip(2).collect(Collectors.toList());

限制元素数量 - limit

返回一个不超过给定长度的流。所需的长度做为参数传递 给limit。若是流是有序的,则最多会返回前n个元素。code

//只返回符合要求的前3个元素
List<User> dishLimits = userList.stream().filter(d -> d.getAge() > 30).limit(3).collect(Collectors.toList());

map 操做

接受一个函数做为参数。这个函数会被应用到每一个元素上,并将其映 射成一个新的元素

//转为字符串长度的集合
List<String> words = Arrays.asList("Hello", "World");
List<Integer> wordLens = words.stream().map(String::length).collect(Collectors.toList());

flatmap 操做

flatmap 方法让你把一个流中的每一个值都换成另外一个流,而后把全部的流链接起来成为一个流。

//使用flatMap找出单词列表中各不相同的字符
List<String> words = Arrays.asList("Hello", "World");
List<String> wordMap = words.stream()
      .map(word -> word.split(""))
      .flatMap(Arrays::stream).distinct().collect(Collectors.toList());

排序 - sorted

sorted 方法用于对流进行排序。如下代码片断使用 sorted 方法对输出的 10 个随机数进行排序:

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

Collectors 聚合操做

Collectors 类实现了不少归约操做,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

查找和匹配

查找和匹配操做包含anyMatch,allMatch,noneMatch,findFirst,findAny,通常状况下使用的少

reduce归约操做

reduce操做是如何做用于一个流的:Lambda反复结合每一个元素,直到流被归约成一个值。reduce方法接受两个参数:一个初始值,这里是0;一个 BinaryOperator<T> 来将两个元素结合起来产生一个新值, 这里咱们用的是 lambda (a, b) -> a + b 归约操做包含sum(元素求和)、min(最小值)、max(最大值)、count(求总数)

总结

  • Stream每一个操做都是依赖Lambda表达式或方法引用。
  • Stream操做是一种声明式的数据处理方式。
  • Stream操做提升了数据处理效率、开发效率。

鼓励把新的Java8特性引入到目前的项目中,一个长期配合的团队以及一门古老的编程语言都须要不断的注入新活力,不然不进则退

[]