Java8引入了流-Stream API,
流:java API的一个新成员,使用这个api可以简明高效的处理数据集,可以理解成遍历数据集的内部迭代器。
简明:使用声明式方查询语句来表达,无需临时编写实现代码。
高效:可以透明的进行并行处理。
使用旧例子: 对菜单中的菜品进行过滤,找出符合条件的菜肴
/**
* 菜品
*/
@Data
@AllArgsConstructor
public class Dish {
private final String name; //菜名
private final boolean vegetarian; //是否为素菜
private int calories; //菜的热量
private final Type type; //菜的类型
public enum Type{ MEAT,FISH,OTHER}
}
List menuNames=menu.stream() //1:从menu获取流
.filter(d->d.getCalories()>300) //2:筛选出高热量的菜品
.map(Dish::getName) //3:使用映射获取菜品名称
.limit(3) //4:截短只取前三个符合条件的结果
.collect(Collectors.toList()); //5:结束流操作,将流保存到另外一个List中
使用上面的一句代码就可以实现这个复杂的操作。
源:流的数据来源,比如集合、数组或输入输出资源(有序集合生成的流元素顺序和原有集合一致)
元素序列:流就像集合一样提供了接口,是一组特定元素类型的有序值。(集合侧重数据存储,流侧重数据计算)
流处理操作:流的数据处理功能支持类似于数据库的声明式操作,以及函数式编程的常用操作,如filter,map,reduce,find,match,sort等,即可顺序执行,也可并行执行。
流水线:多个流操作链接起来,就形成了一个流水线,可以看做是是一种类似于数据库式的查询式处理。
内部迭代:流的迭代操作是在背后操作的,而非像迭代器那样进行显示迭代。
3.1流与集合的区别
集合 是一个内存中的数据结构,它包含数据结构中目前所有的值-集合中的每个元素都得先计算出来才能添加到集合当中。
流 则是概念上固定的数据结构,不能删除或添加元素,元素按需计算;是一种“生产者-消费者”的关系,就像一个延迟创建的集合,只有消费者要求时才会计算值。
3.2 使用流的代码具有以下特点
声明性:使用声明式方查询语句,简洁易懂。
可复合:Stream API方法可灵活结合使用。
可并行:内部对并行做了处理,使用者可以不用关心并行
除此之外,还有其他特点:
流只能遍历一次:流和迭代器一样,只能遍历一次,一旦遍历完,这个流就被消费掉了,除非你再从原始数据重新获取一个流。
流使用内部迭代:Stream ApI帮你把迭代做了,并将流值保存在某个地方,你只要给出函数说要干什么就行了。
Java8引入流的理由:Stream库的内部迭代可以自动选择符合硬件的数据表示和并行实现。
还是上面的例子: menu.stream().filter(d->d.getCalories()>300).map(Dish::getName).limit(3).collect(Collectors.toList());
所以,使用流包括了三部分:
一个数据源:比如集合。
一个中间操作链:形成一条流的流水线。
一个终端操作:执行流水线,能生成结果。
其中,诸如filter,map,limit这样的操作都叫做中间操作,它们都会返回另外一个流给其他中断操作使用,所以中间操作方法是可以联合起来使用。除非它们遇到终端操作,一次性处理完所有的流。
终端操作则会从流水线上生成结果。生成非流值,比如List,Integer,void
常用的流操作
filter:谓词筛选,接受一个谓词(返回boolean的函数,如:.filter(Dish::isVegetarian))
distinct:筛选掉重复元素(.distinct())
limit:截短流(.limit(n)),方法返回不超过n个元素
skip:跳过元素(.skip(n)),扔掉钱n个元素
map:映射(.map(func)),,接受一个函数,该该函将每个元素映射成另外一个元素。
flatMap:流的扁平化,将流中的所有块,映射成一个流的内容,拆分了流中的块。
短路操作:一旦匹配中,就停止计算流,返回boolean结果。
anyMatch:流中是否有一个元素能匹配给定的谓词(.anyMatch(Dish::isVegetarian))
allMatch:它会判断流中的元素是否都能匹配中谓词,例子同上
noneMatch:它会确保每个元素无法匹配中,一旦有匹配中的就返回false
上面的都是短路操作,limit也是短路操作。
查找元素
.findAny()
.findFirst()
归约:将流中所有元素结合起来得到一个值(流规约为一个值)
numberList.reduce(0,(a,b)->a+b)