Stream是Java8的一个新特性,隶属于java.util包下,它是一个接口类型,里面定义了各种方法方便用于对各类集合进行操作,极大的简化了开发效率。
Stream 就类似于一个高级的迭代器,但只能遍历一次,在这过程中也可以对流中的元素执行一些操作,使用forEach方法对集合进行快速的遍历,过滤掉任意长度的字符串、获取每个字符串的首字母,转换数据类型等。
Stream流式思想类似于工厂车间的 “生产流水线”,Stream流不是一种数据结构,它不用于保存数据,而是对数据进行加工处理,可以看作为流水线上的一道工序,通过多道工序让一个数据原材料加工成一个商品再对外开放。
第一种是通过Collection接口的stream方法获取
//创建一个List集合对象
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
第二种是通过Collection接口的parallelStream方法获取一个并发流
//创建一个list集合
List<String> list = new ArrayList<>();
Stream<String> parallelStream = list.parallelStream();
第三种是通过Stream接口里的of方法获取数组对应的流
Stream<Object> of = Stream.of(); //直接用Stream接口调用自身的of方法
of方法有两个参数,一个是根据泛型传参,一个是可变长参数类型
List<String> list = new ArrayList<>();
Stream<Object> of1 = Stream.of(list); //传入一个list集合,也可以是其它类型
Stream<Integer> of2 = Stream.of(1, 2, 3); //根据可变参数传值,可以是任意长度
Stream流的操作流程是先将集合转为流,然后经过各种循环遍历和筛选的操作,比如过滤、筛选、分组、计算。和最后的计数操作,然后转化成想要的数据,这个数据的形式还是集合本身,也可以按照需求利用count求总数
原始集合 ===> Stream流 ===>筛选操作(遍历、过滤、分组、统计) —> 最终结果
使用某一种技术本质上还是为了提高开发效率,减少代码的冗余,Stream流可以帮助我们高效的去操作集合
,通过生产流水线
的方式对集合进行删除
、合并
、排序
、修改
,并最终返回想要的元素数据或统计数据。这里流水线
的意思是说,一批数据元素不需要等待全部元素都完成某些操作才进行下步流程操作,而是可以尽可能的进行下步操作,就好像流水线工厂一样,这为Stream流高效运作提供了基础。Stream流还有一个内部迭代
的概念,就是把for循环显示迭代封装了起来,这样可以更方便的并行开发
。
方法名 | 方法作用 | 返回值类型 | 方法种类 |
---|---|---|---|
forEach | 逐个遍历元素 | void | 结尾 |
filter | 过滤流元素 | Stream | 方法拼接 |
map | 映射流 | Stream | 方法拼接 |
skip | 跳过前几个元素 | Stream | 方法拼接 |
distinct | 去除重复的元素 | Stream | 方法拼接 |
limit | 取前几个元素值 | Stream | 方法拼接 |
count | 统计总数 | long | 结尾 |
concat | 组合 | Stream | 方法拼接 |
forEach参数是名为Consumer的接口(Java8的一个函数式接口,这个参数没有返回值,后面也不能再接其它的流方法,其参数语法为 类名 :: 方法名,一般用System类调用print或println方法
示例:
Stream<String> stream = Stream.of("Im","a","stream");
stream.forEach(System.out::print); //print不会换行
stream.forEach(System.out::println); //print不会换行
filter是过滤器的意思,顾名思义就是用来过滤集合元素然后再将其结果打印输出
例如过滤筛选出流中等于10的元素
Stream<Integer> stream = Stream.of(10,20,30);
//使用lambda表达式筛选出等于10的值,然后再调用forEach遍历输出
stream.filter(F -> F == 10).forEach(System.out :: print);
调用String类的方法对字符串进行筛选过滤
Stream<String> stream = Stream.of("I'm","a","stream");
//String类的contains方法,指定包含某个值然后打印输出
stream.filter(F-> F.contains("stream")).forEach(System.out :: print);
这个方法可以把流中初始的元素转换成新的流元素,例如泛型中数据类型的转换
List<String> list = new ArrayList<>();
list.add("stream1");
list.add("stream2");
list.add("stream3");
//使用length方法把String类型的流转换为Integer的流
Stream<Integer> stream = list.stream().map(String::length);
stream.forEach(System.out :: print);
skip翻译过来是跳过的意思,在流中可以跳过前边指定的元素,从而执行后面的元素
Stream<Integer> stream = Stream.of(20,30,40,50);
//指定跳过前3个值,流往后执行
stream.skip(3).forEach(System.out :: print);
distinct是去重(第二声)可避免流中存在重复的数据元素,类似于mysql里的distinct关键字。
Stream<Integer> stream = Stream.of(1,1,1,2,3,4,5);
//使用了distinct方法之后流中重复的1元素将不会多次打印
stream.distinct().forEach(System.out :: print);
这个方法用于限制流中的元素,指定元素的前几个长度并输出。
Stream<String> stream = Stream.of("a","stream","method");
// 指定截取前两个元素,也就是三个字符串的前两个值。
stream.limit(2).forEach(System.out :: print);
统计并获取流中元素的个数,此方法是其它类型所以不能进行流方法拼接
Stream<String> stream = Stream.of("this","is","a","count","method");
//调用count方法并用long类型接收
long count = stream.count();
//打印count变量
System.out.println(count);
此方法可以将两个不同的流中的元素合并成一个流进行操作
Stream<String> stream1 = Stream.of("stream01");
Stream<String> stream2 = Stream.of("stream02");
//由于concat被static静态修饰,所以只能由Stream接口去调用
Stream<String> concat = Stream.concat(stream1, stream2);
concat.forEach(System.out :: print);
注意:使用了concat和并流之后不能再调用单独的流进行输出,否则报错
//错误示例
Stream<String> stream1 = Stream.of("stream01");
Stream<String> stream2 = Stream.of("stream02");
Stream<String> concat = Stream.concat(stream1, stream2);
//只调用stream1进行遍历
stream1.forEach(System.out :: println);
reduce
主要作用于把Stream流中的元素组合起来做四则运算
它有两种用法:
一种是通过函数式接口用lambda表达式做运算,返回Optional类
Stream<Integer> stream = Stream.of(10,30);
//需要用get方法取出对应流中泛型的对象
Integer get = stream.reduce((K,V) -> K + V).get();
System.out.println(get); //输出为40
还有一种是通过一个初始值做运算
Stream<Integer> stream = Stream.of(10,30);
//设置一个初始值3去和流中的元素做相加,调用Integer包装类的sum方法
Integer sum = stream.reduce(3, Integer包装类的sum方法::sum);
System.out.println(sum);
判断流中是否存在指定的元素,只要有一个条件成立就返回true,返回值为Boolean类型
Stream stream = Stream.of("anyMatch","b","c");
//调用String类的contains方法判断是否包含指定元素,用==和Object的equals也可以判断
System.out.println(stream.anyMatch(k -> k.contains("a")));
有一个不匹配的元素就返回true,全部匹配才返回true,boolean类型
Stream<String> stream = Stream.of("allMatch","b","c");
//a不是一个单独的元素,对应此方法返回的是false
System.out.println(stream.allMatch(a -> a.contains("a")));
如果匹配的元素和流中有一个相匹配就返回 false,否则只有都不相同的时候才返回 true
Stream<String> stream = Stream.of("a","b","c");
//流中没有d元素,所以此时才会返回true值
System.out.println(stream.noneMatch(n -> n.contains("d")));
此方法可以将Stream流转换为集合进行操作
List<String> list = new ArrayList<>();
list.add("collect--01");
list.add("collect--02");
list.add("collect--03");
Stream<String> stream = list.stream();
//转换为List集合
List<String> list1 = stream.collect(Collectors.toList());
//转换为Set集合
Set<String> set = stream.collect(Collectors.toSet());
//使用Collectors类调用字符串拼接方法,使用过逗号分割
String collect = stream.collect(Collectors.joining(","));
//输出为:collect = collect--01,collect--02,collect--03
System.out.println("collect = " + collect);