Stream流了解到使用
stream
概述
Stream流是jdk1.8对集合对象功能的增强
集合 –> 流模型
通过声明的方式对集合中的每个元素进行一系列并行或者串行的流水线操作
性质
它是一个高级版本的迭代器Iterator
Stream只要给出其他包含的元素执行操作,就会隐式的在内部进行遍历
它会将集合转化为Stream流,然后将流在管道中经过中间操作的处理,最后由最终操作,得到前面处理的结果。。
使用
使用流程我们可以大致分为三个步骤
1. 获取一个数据源:集合的原始数据类型
这里我要补充一点就是,流不是数据结构不能保存数据,它是一个处理工具,所以我们需先创建一个集合或者数组,用来存储数据。
2. 转化为流:将List –> Stream
创建流可以按照这个两大类进行划分
- 串行化(单线程操作):stream
- 并行化(多线程并发操作):parallelStream
具体到不同的集合又可以通过不同的数据结构进行划分
- 直接通过stream创建
Stream<Integer> streamList = Stream.of(1, 2, 3, 4);
- 通过集合创建创建(最常用)
ArrayList<String> list = new ArrayList<>();
list.add("10");
list.add("20");
Stream<String> streamList = list.stream();
- 通过文件创建
try {
Stream<String> fileStream = Files.lines(Paths.get("xxx.txt"), Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
}
-
通过函数创建
无限流:如上所述,Stream流不会自己存储元素,并且不会改变源对象,每次都返回一个新的Stream,只有操作触发,才会进行处理,称为惰性求值,而无限流就是每次都会进行迭代,并调用apply方法更新元素返回新的流,如果不进行中间操作,在终止的会无限执行上述步骤。’
下面就是使用两种不同的函数进行创建
第一种:iterate
// 初始化值 函数操作 因为iterate是截断流操作所以需要使用终止操作
Stream.iterate(0, n -> n++ ).limit(3).forEach(System.out::println);
至于什么是终止符后面我会介绍
第二种:generator
// 只接收一个参数由它为流提供值
Stream.generate(Math::random).limit(5).forEach(System.out::println);
3. 执行操作:针对Stream进行操作
操作符就像是流水线上的工人,只有熟悉每个操作符才能熟练掌握Stream的操作。下面我就分别介绍Stream中的操作符。
中间操作符
在对流操作之后,还会可以向下继续传导操作的,我们称为中间操作符
大致分为下述四类
-
筛选和切片
- filter:过滤操作,取出满足条件的数据,返回一个新的Stream
- skip:跳过
- limit:限流操作
- distinct:去重操作,底层采用流元素中的hashCode()和equals()进行对比
-
映射
- map:转化操作符,可以将一个A转化为一个B
- flatMap:可以将一个A转化为多个B
-
排序
- sorted:使用comparable和Comparator接口
-
消费
- peek:跳出操作
终端操作符
对数据进行消费或者收集,不会继续向下传导
-
收集操作
恒等处理:
将集合转化为其他形式:Set、List、Map集合
例:// 转化为List集合 List<String> collectList = list.stream().collect(Collectors.toList()); // 转化为Set集合 Set<String> collectSet = list.stream().collect(Collectors.toSet());
规约处理:
对其集合进行合并,排序,求和等操作
例:// 对集合进行拼接 String joinStr3 = list.stream().map(s->s.getName()).collect(Collectors.joining("—","",">_<")); // 求最大 list.stream().collect(Collectors.maxBy((s1,s2)->Integer.parseInt(s1)-Integer.parseInt(s2))).get();
分组处理:
对集合进行分组例:
// 按照子公司维度将员工分组 Map<String, List<Employee>> resultMap = getAllEmployees().stream() .collect(Collectors.groupingBy(Employee::getSubCompany)); System.out.println(resultMap);
-
统计操作
这个比较好理解,直接统计流中个数.System.out.println(list.stream().count());
-
查找操作
查找操作大致有两个:findFirst,findAll
一般用于检查流中的元素,返回数据类型为Optional//findFirst一般返回流中的第一个元素 strings.stream().findFirst().get(); //findAny一般返回流中的第一个元素 strings.stream().findAny().get();
这两个流虽然只有在多线程环境下,返回的结果可能不一样
-
匹配操作
- anyMatch:判断的条件里,任意一个元素成功,返回true
- allMatch:判断条件里的元素,所有的都是,返回true
- noneMatch:与allMatch相反,判断条件里的元素,所有的都不是,返回true
下面我就举一个例子方便理解:
//匹配条件
System.out.println(Stream.of(1, 23, 34, 35, 21).anyMatch(i -> i > 50));
//最终返回false,无符合条件
-
最值操作
使用max和min即可找出一些最值,这个比较简单不代码演示了 -
遍历操作
直接使用forEach
list.stream().limit(3).forEach(System.out::println);
针对不同的操作,使用不同的操作符
最终得到想要的结果
总结