
用好强大的Stream
函数式接口
众所周知,Java8提供了很多新的特性,Lambda表达式,函数式接口,Optional,新的日期类api。今天简单聊一下Stream的前世今生。
Lambda表达式我们现在已经用的很多了,而函数式接口则是为了支持Lambda表达式,Java8提供了很多内置的函数式接口,如Runnable,Comparator等是从原有的API升级来的,而有些是Java8新增的,如Consumer等。
类上有注解@FunctionalInterface就可以认为这是一个函数式接口,可以用在Lambda表达式中。Lambda表达式极大的简化了我们的编程
为了方便我们使用Lambda表达式,Java8提供了一些内置的函数式接口
函数式接口 | 方法 | 用途 |
Consumer<T> 消费型接口 | void accept(T t) | 输入参数为T,没有返回 |
Supplier供给型接口 | T get() | 返回R |
Function<T, R> 函数型接口 | R apply(T t) | 输入参数为T,返回为R |
Predicate判断型接口 | boolean test(T t) | 对象是否满足条件,true为满足,false为不满足 |
Java8为什么要新提供这些函数式接口呢?
我举个例子你就明白了。
员工对象为Person,此时老板发话了,给我找出年龄大于20的员工把,于是就有了下面的方法
干的不错,再给我找一下工资大于2000的员工把。
再给我找一下,,, 老板等等,我需要优化一下这个实现。
你发现问题了吗?2个方法只有判断条件不同,其余的部分一模一样。而且可扩展性太差,该怎么优化呢?
额,我们可以定义一个如下的接口,判断的逻辑让接口的实现类去实现
上面的需求就可以用如下几行代码实现。
此时老板再加筛选需求也不怕了。
等等,我们定义的Predicate接口和Java8内置的函数式接口好像。哈哈,基本上一模一样,因为类似的场景很多,所以Java8帮我们定义了一系列的接口。省的我们自己定义
函数式接口的使用
函数式接口 | 方法 | 用途 |
Consumer<T> 消费型接口 | void accept(T t) | 输入参数为T,没有返回 |
Supplier供给型接口 | T get() | 返回R |
Function<T, R> 函数型接口 | R apply(T t) | 输入参数为T,返回为R |
Predicate判断型接口 | boolean test(T t) | 对象是否满足条件,true为满足,false为不满足 |
当然,为了方便我们的使用,还有很多其他的内置接口,看入参和返回值就能知道接口的作用
函数式接口 | 方法 |
BiFunction<T, U, R> | R apply(T t, U u) |
BiConsumer<T, U> | void accept(T t, U u) |
ToIntFunction | int applyAsInt(T value) |
IntFunction | R apply(int value) |
Stream介绍
在Java8之前,如果我们想对集合进行操作还是比较麻烦的。Java8设计了Stream API来简化对集合的操作,Stream API的设计基于函数式编程和lambda表达式,行云流水似的编程方式给人带来新的体验。
Stream操作分为如下三个步骤
- 创建Stream:从数据源,例如集合,数组中获取一个流
- 中间操作:对数据进行处理
- 终止操作:执行中间操作,并产生结果。一般返回void或一个非流的结果
注意当不执行终止操作的时候,中间操作不会执行
创建Stream
中间操作
筛选与切片
函数名 | 解释 |
filter | 从流中排除某些元素 |
limit | 使元素不超过指定数量 |
skip | 跳过前n个元素,如果流中元素不超过n个,则返回一个空流 |
distinct | 通过hashCode()和equals()去除重复元素 |
看一下filter方法和forEach方法的定义
Stream.java
这不就是我门上面介绍的函数式接口吗?很多方法的入参其实就是一个函数式接口
映射
函数名 | 解释 |
map | 接收一个函数作为参数,该函数被应用到每个元素上,并将其映射成一个新的元素 |
flatMap | 接受一个函数作为参数,将流中的每一个值都转换成另一个流,然后将所有流连接成一个流 |
先看这2个方法的定义
map方法的入参和返回值可以为任意值 flatMap方法的入参为任意值,返回值必须为Stream
解释一下这个输出,x.split("")后为数组,所以第一个输出的为数组的地址 第二个x.split("")后为数组,然后将多个数组转为多个流,将多个流合并后输出
排序
函数名 | 解释 |
sorted() | 自然排序,通过Comparable接口定义的规则来排序 |
sorted(Comparator) | 定制排序,通过Comparator接口定义的规则来排序 |
终止操作
查找与匹配
函数名 | 解释 |
allMatch | 是否匹配所有元素 |
anyMatch | 是否至少匹配一个元素 |
noneMatch | 是否没有匹配所有元素 |
findFirst | 返回第一个元素 |
findAny | 返回当前流中的任意元素 |
count | 返回当前流中元素总个数 |
max | 返回流中最大值 |
min | 返回流中最小值 |
归约
函数名 | 解释 |
reduce | 归约,将流中元素反复结合起来得到一个值 |
收集
用collect方法来进行收集,方法定义如下
Stream.java
当然我一般不自己实现这个接口,可以直接用Collectors工具类
一些使用Demo
枚举值参数校验
项目中有很多单选项需要定义相关的枚举值,前端传入后需要校验这些值是否在枚举范围内
调用远程服务前存对应关系
根据学生姓名获取学生的其他信息
- 先存学生姓名->学生的映射关系为nameMap
- 通过学生姓名调用其他服务批量获取学生信息
- 从nemeMap中根据其他服务返回的学生姓名拿到Student,然后填充信息到Student
文章转载自公众号:Java识堂
