强大的链式编程 Stream API :Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。
所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。
Lambda 表达式 本质是匿名方法
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Lambda表达式只能出现在目标类型为函数式接口的上下文中
表达式: (参数列表) → { 语句块 };
比如:声明一个方法
public int sum(int i,int j){ return i+j; }
转换成lambda表达式后可以写成
(int i,int j)→ i+j;
参数的类型也是可以省略的,Java编译器可以过根据上下文感知到参数类型:
(i,j)→ i+j; 或者 (i,j)→ { retrun i+j;}
可见:Lambda 表达式有三部分组成:参数列表 ,箭头(→) ,以及 语句块
接下来由浅入深通过四种简化方式简化一下:
展开原码
Lambda表达式方法引用简化
java中的双冒号操作符 ::
定义
双冒号运算操作符是类方法的句柄,lambda表达式的一种简写
范式: 类名 :: 方法名
注意:
方法后面并没有()
懒加载方法是否调用要看调用方使用情况
有时候已经有其他方法实现了函数接口的方法了,那么我们可以直接引用此方法代替函数接口的实现方法,常见的引用形式有以下语法:
调用方法简化
静态方法引用:ClassName :: methodName
实例方法引用:object :: methodName
超类方法引用:super :: methodName
构造方法简化
构造方法引用:ClassName::new
数组构造引用:TypeName[]::new
什么是流 Stream API
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。
原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;
高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
流的构成:
当我们使用一个流的时候,通常包括三个基本步骤:
获取一个数据源(source) → 数据转换 → 执行操作获取想要的结果。
创建Stream;
转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(**可以有多次转换**);
对Stream进行聚合(Reduce)操作,获取想要的结果;
每次转换原有的Stream对象不改变,返回一个新的Stream 对象(可以有多次转换),这样就允许对其操作可以像链条一样排列,变成一个通道。
第一步:获取数据源 创建stream
Collection接口的stream()或parallelStream()方法
静态的Stream.of()、Stream.empty()方法
Arrays.stream(array, from, to)
静态的Stream.generate()方法生成无限流,接受一个不包含引元的函数
静态的Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数
Pattern接口的splitAsStream(input)方法
静态的Files.lines(path)、Files.lines(path, charSet)方法
静态的Stream.concat()方法将两个流连接起来
。。。。
第二步: 中间操作(中间操作不会执行任何操作,直到执行了终止操作时,才会一次性执行所有中间操作, 侧面说明了流是惰性的 ):转换Stream 比如 筛选和过滤 映射
筛选和过滤
Stream<T> filter(Predicate<? super T> predicate)
filter() : 接受一个lambda表达式 (自定以过滤条件 ,返回 boolean),从流中排除某些元素。
Stream<T> limit(long maxSize)
limit(maxSize):截取前maxSize元素的流。但已经满足返回添加,可发生短路,不再继续执行流
Stream<T> skip(long n)
skip(N): 跳过元素,返回一个扔掉了前个元素的流,如流中的元素不满足N 个,则返回一个空流。 与limit() 互补
Stream<T> distinct()
distinct(): 筛选去重,通过流所生成元素的 hashCode() 和equals() 去除重复的元素。 需要重写类的 hashCode() 和equals() 方法
映射:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map(): 接受一个函数 Function 作为参数,该函数会作用到每个元素上,并将其映射称为一个新的元素。然后返回一个Stream<R> ( 接收Lambda ,将元素转换成其他形式或提取信息)
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
flatmap() : 接受一个函数 Function 作为参数,将流Stream中的每一个值都换成另一个流Stream,然后将所有的流 合并成一个流 ,然后返回一个Stream<R>
比较map() 和 flatmap方法可以类比 集合中的 add() 和 addAll() 方法。
排序:
Stream<T> sorted()
sorted(): 自然排序 ,根据Comparable 进行排序。Stream<T> sorted(Comparator<? super T> comparator)
sorted(Comparator): 根据Comparator 排序,可自定义排序规则
第三步:终结操作
查找元素:
boolean allMatch(Predicate<? super T> predicate)
allMatch(Predicate): 流中所有的元素都能够满足 定义的断言规则 就会返回true ,若存在一个元素不满足断言规则,则返回false。
boolean anyMatch(Predicate<? super T> predicate)
anyMatch(Predicate): 流中任何一个元素能够 满足定义的断言规则 就会返回true ,若所有元素都不满足断言规则,则返回false。
boolean noneMatch(Predicate<? super T> predicate)
noneMatch(Predicate): 流中所有元素都无法匹配 定义的断言规则 就会返回true, 若存在一个元素满足断言规则,则返回false。
Optional<T> findAny()
findFirst(): 返回第一个元素
Optional<T> findAny()
findAny() :返回任意元素,随机返回
组函数:
max(Comparator):返回指定比较规则 的最大值 对应的元素
min(Comparator):返回 指定比较规则 的最小值 对应的元素
count() :返回流中元素的个数
归约
T reduce(T identity, BinaryOperator<T> accumulator)
reduce(a, fun) a为起始值,作为累积器的起点,reduce方法可以将该流中元素反复结合起来,得到一个新值 类型为T ,该值不可能为空,至少也是 起始值a。
Optional<T> reduce(BinaryOperator<T> accumulator) (可能为空的值需要封装进Optional 中)
reduce(fun) 从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数。
可结合map形成 map-reduce 模式
收集
<R, A> R collect(Collector<? super T, A, R> collector)
collect(Collector) :将流转换为其他形式,接受一个收集器Collector,用于给stream中的元素做汇总方法
Collector接口中方法的实现决定了如何对流执行收集操作(如:收集到List set map),但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器的实例,具体方法与实例如下表:
Collectors.toList() 收集到list集合中
Collectors.toSet() 收集到set 集合中
Collectors.toCollection 收集到指定类型的集合中去, 比如收集到HashSet中 HashSet<String> hs= ObjectStream.collect(Collectors.toCollection(HashSet::new ))
Collectors.toMap(fun1, fun2) / toConcurrentMap(fun1, fun2) 两个fun用来产生键和值,若值为元素本身,则fun2为Function.identity()
Collectors.toMap(fun1, fun2, fun3) / toConcurrentMap(fun1, fun2, fun3) fun3用于解决键冲突,例如(oldValue, newValue) -> oldValue,有冲突时保
还有 计算 平均值 averagingInt/averagingLong/avergingDouble 最大值maxBy 最小值minBy 总和summingInt/sunmmingLong/summingDouble 分组groupingBy 分区 partitioningBy 组函数合辑 summarizingInt
等等方法
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
collect(fun1, fun2, fun3) :fun1转换流元素;fun2为累积器,将fun1的转换结果累积起来;fun3为组合器,将并行处理过程中累积器的各个结果组合起来
forEach(fun) 遍历流中的元素
forEachOrdered(fun) 指定遍历的顺序,遍历流中的元素。 可以应用在并行流上以保持元素顺序
toArray()
toArray(T[] :: new) 返回正确的元素类型