Stream概述
Stream流是jdk1.8对集合对象功能的增强,可以通过将集合转换为流模型,通过声明的方式对集合中的每个元素进行一系列并行或者串行的流水线操作。
Stream只要给出对其包含的元素执行什么操作,Stream就会隐式地在内部进行遍历,并给出响应的数据转换。
Stream可以并行化操作,Stream的并行操作是依赖Java7中引入的Fork/Join框架拆分任务和加速处理过程,并且允许数据源是无限的。
基本的执行流程
使用Stream通常包括3个基本步骤:获取数据源source -> 转换为流 -> 执行操作 -> 获取所想要的结果。每次转换原有的Stream对象,执行结果还是Stream,可以使用串式写法定义多个操作。
- 将
List<T>
集合转换为Stream<T>
- 针对Stream进行一系列操作,每次操作结束返回还是Stream。
- 可以将Stream转换回集合类型,也可以直接对其中的元素进行处理。
获取Stream
流Stream既可以是串行顺序的stream,也可以是并行的parallelStream。顺序流的操作是在单线程上执行,而并行流是在多线程上并发执行的。
通过集合获取
Arrays.stream(arr)
可以使用 Arrays.stream 将一组数据转换为Stream。
Integer[] arr =newInteger[]{3,4,5,6,78,4};long count =Arrays.stream(arr).filter(i -> i>20).count();System.out.println("count="+ count);
输出:
count=1123456
list.stream()
使用Collection.parallelStream使用并行流,处理任务并行执行。
List<Integer> list =Arrays.asList(1,2,3,4,5,6);Stream<Integer> stream = list.parallelStream();
stream.forEach(System.out::print);System.out.println("\n++++++");Stream<Integer> stream2 = list.stream();
stream2.forEach(System.out::print);
输出:
456321++++++123456123456789101112
parallelStream在使用上和stream没有区别,本质上返回的都是一个流,只不过底层处理时会根据执行环境的条件判断时并行还是串行。
Stream.of()
Integer[] arr =newInteger[]{3,4,5,6,78,4};List<Integer> list =Arrays.asList(1,2,3,4,5,6);Stream.of(arr).forEach(System.out::println);Stream.of(list).forEach(System.out::println);
输出:
3456784[1,2,3,4,5,6]1234567891011121314
基本类型Stream
对于基本类型目前有3中对应的包装类型Stream:
IntStream
、
LongStream
和
DoubleStream
。如果不使用对应的Stream类型,也可以使用 Stream、Stream 和 Stream ,但是针对元素进行装拆箱操作比较耗时,所以才有了常用的基本数据类型的对应Stream。
//参数类型为int...不确定个数的参数,可以根据参数生成一个streamIntStream.of(3,5,18,1,4).forEach(System.out::println);//根据指定的返回生成一组连续值,1-10含左不含右IntStream.range(1,10).forEach(System.out::println);//根据指定的返回生成一组连续值,10-20含左含右IntStream.rangeClosed(10,20).forEach(System.out::println);12345678
从输入流中获取数据的方法
BufferedReader类方法
lines()
返回Stream
BufferedReader br =newBufferedReader(newFileReader("data.txt"));Stream<String> stream = br.lines();
stream.foreach(System.out::prinln);123
转换操作
Stream的操作符基本可以分为转换操作和聚合操作两大类,转换操作符会继续向下传递,聚合操作符直接对数据进行消费或者收集,不会继续向下传递。
- 转换操作操作符 -
map
:转换操作符,用于映射每个元素到对应的结果-flatMap
:合并转换-filter
:过滤操作,过滤满足条件的数据-limit
:限流操作-skip
:跳过操作-distinct
:去重操作,底层采用equals进行比对-peek
:跳出操作-sorted
:排序操作,Comparable和Comparator接口
map
map
方法用于映射每个元素到对应的结果,转换操作函数当做参数传入方法。
List<Integer> list =newArrayList<Integer>();
list.add(15);
list.add(32);
list.add(67);
list.add(232);System.out.println(list);//将Integer类型的元素映射转换为String类型List<String> result = list.stream().map(i ->String.valueOf(i)).collect(Collectors.toList());System.out.println(result);
将Integer类型的元素映射转换为String类型,再过滤字符串长度大于2的元素
List<String> result2 = list.stream().map(i ->String.valueOf(i)).filter(bb -> bb.length()>2).collect(Collectors.toList());System.out.println(result2);
输出:
[15,32,67,232][15,32,67,232][232]123456789101112131415161718
mapToInt、mapToLong、mapToDouble
用于 统计 结果收集器产生统计结果值,主要用于int、long、double等基本类型。
List<Integer> nums =Arrays.asList(3,2,2,3,7,3,5);IntSummaryStatistics stats = nums.stream().mapToInt((x)-> x).summaryStatistics();System.out.println("最大值:"+stats.getMax());System.out.println("最小值:"+stats.getMin());System.out.println("所有数据之和:"+stats.getSum());System.out.println("所有数据的平均值:"+stats.getAverage());System.out.println("所有数据的个数:"+stats.getCount());
输出:
最大值:7
最小值:2
所有数据之和:25
所有数据的平均值:3.5714285714285716
所有数据的个数:71234567891011121314
元素是类
HashSet<Product> products =newHashSet<>();
products.add(newProduct("product1","11.2"));
products.add(newProduct("product2","22.3"));
products.add(newProduct("product3","33.4"));double sum = products.stream().mapToDouble(v ->Double.valueOf(v.getPrice())).sum();double max = products.stream().mapToDouble(v ->Double.valueOf(v.getPrice())).max().getAsDouble();double min = products.stream().mapToDouble(v ->Double.valueOf(v.getPrice())).min().getAsDouble();double average = products.stream().mapToDouble(v ->Double.valueOf(v.getPrice())).average().getAsDouble();long count = products.stream().mapToDouble(v ->Double.valueOf(v.getPrice())).count();System.out.println("最大值:"+ max);System.out.println("最小值:"+ min);System.out.println("所有数据之和:"+ sum);System.out.println("所有数据的平均值:"+ average);System.out.println("所有数据的个数:"+ count);
输出:
最大值:33.4
最小值:11.2
所有数据之和:66.9
所有数据的平均值:22.3
所有数据的个数:31234567891011121314151617181920212223
注:
max()
、
min()
、
average()
获取的是 OptionalDouble类型,需要调用
getAsDouble()
返回double类型。
flatMap
flatMap
将多个流合并,比如,将
List<List<String>>
通过flatMap函数可以变为
List<String>
List<Integer> list1 =newArrayList<>();
list1.add(34);
list1.add(25);
list1.add(35);List<Integer> list2 =newArrayList<>();
list2.add(999);
list2.add(888);
list2.add(999);
list2.add(666);List<List<Integer>> tesList =newArrayList<>();
tesList.add(list1);
tesList.add( list2);List<Integer> result = tesList.stream().flatMap(num -> num.stream()).collect(Collectors.toList());System.out.println(result);
输出:
[34,25,35,999,888,999,666]1234567891011121314151617181920
属性合并
合并两个 list< map >, 并将userId 相同的所有属性合并到一个 map 中。
list1中对象的属性:userId、userName
list2中对象的属性:userId、gender、age
最总集合中对象的属性:userId、userName、gender、age
publicclassMergeStream{publicstaticvoidmain(String[] args){List<Map<String,Object>> list1 =newArrayList<>();Map<String,Object> data=newHashMap<>();
data.put("userId","100001");
data.put("userName","唐僧");
list1.add(data);List<Map<String,Object>> list2 =newArrayList<>();
data=newHashMap<>();
data.put("userId","100001");
data.put("gender","男");
data.put("age",20);
list2.add(data);List<Map<String,Object>> collect = list1.stream().map(m1 ->{
list2.stream().filter(m2 -> m1.get("userId").equals(m2.get("userId"))).forEach(m2 ->{
m1.put("gender", m2.get("gender"));
m1.put("age", m2.get("age"));});return m1;}).collect(Collectors.toList());System.out.println(collect);}}
输出:
[{gender=男, userName=唐僧, userId=100001, age=20}]1234567891011121314151617181920212223242526272829
更多操作详见:jdk8使用stream实现两个list集合合并成一个(对象属性的合并)
filter
filter
方法用于对传入的数据流进行过滤处理,只返回满足条件的数据组成的新的数据流。
List<Integer> list =newArrayList<Integer>();
list.add(15);
list.add(32);
list.add(67);
list.add(232);System.out.println(list);List<Integer> result = list.stream().filter(i -> i>50).collect(Collectors.toList());System.out.println(result);
输出:
[15,32,67,232][67,232]1234567891011121314
limit
limit
方法会返回一个包含指定个数元素的新stream,如果原始数据总长大小不足则返回原始流。
List<Integer> list =newArrayList<Integer>();for(int i =0; i <10; i++){
list.add(i);}List<Integer> result = list.stream().limit(5).collect(Collectors.toList());System.out.println(result);
输出:
[0,1,2,3,4]1234567891011
skip方法
skip
方法的含义是跳过多少个元素,继续处理后续元素。
List<Integer> list =newArrayList<Integer>();for(int i =0; i <10; i++){
list.add(i);}List<Integer> result2 = list.stream().skip(5).collect(Collectors.toList());System.out.println(result2);
输出:
[5,6,7,8,9]1234567891011
distinct
distinct
会根据原始流中的元素返回一个具有相同顺序,剔除了重复值的流。
List<Product> list =newArrayList<Product>();
list.add(newProduct("product1","11.2"));
list.add(newProduct("product2","22.3"));
list.add(newProduct("product3","33.4"));
list.add(newProduct("product1","11.2"));List<Product> list2 = list.stream().distinct().collect(Collectors.toList());System.out.println(list2);
输出:
[Product{name='product1', price='11.2'},Product{name='product2', price='22.3'},Product{name='product3', price='33.4'}]1234567891011
元素Product需要重写
hashCode()
和
equals()
方法。
sorted
sorted
方法是遍历整个流的所有数据,并且在产生任何数据元素之前对它进行排序。需要实现 Comparable接口 和 Comparator接口。
List<Integer> list =newArrayList<Integer>();
list.add(10);
list.add(39);
list.add(10);
list.add(78);List<Integer> result =list.stream().sorted(Integer::compareTo).collect(Collectors.toList());System.out.println(result);
输出:
[10,10,39,78]123456789101112
聚合操作
见下章《Stream流 - 聚合操作和遍历操作》
参考文章:
《Java学习笔记——Stream流》
版权归原作者 Jothan Zhong 所有, 如有侵权,请联系我们删除。