JDK 1.8-Stream中常用的API
1. Stream
Stream是一组用来处理数组,集合的API
1.1特性
- 不是数据结构,没有内部存储
- 不支持索引访问
- 延时计算
- 支持并行
- 很容易生成数据或集合
- 支持过滤,查找,转换,汇总,聚合等操作
1.2缺点
- 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。
- 不容易使用debug模式调试。
- 在 lambda 语句中直接强制类型转换不方便。
- 不可以在foreach中修改foreach外面的值。
1.3 运行机制
Stream分为源source,中间操作,终止操作。一个流只会有一个终止操作,Stream只有遇到终止操作,它的源才会开始执行遍历操作。一个流只能使用一次。
1.3 Stream的创建
1.通过数组
String[] str={“a”,”b”,”c”}
Stream str1=Stream.of(str);
2.通过集合
List list=Arrays.asList(“a”,”b”,”c”);
Stream stream=list.stream();
3.通过iterate
Stream iterate=Stream.iterate(1,X->x+1);
Iterate.forEach(x->System.out.println(x));
2. Stream常用的API
2.1中间操作
2.1.1 filter过滤
Filter会根据条件截取流中符合条件的数据。
List integerList=Arrays.asList(1,2,3,4,5,6);
List collect=integerList.stream().filter(i->i%2==0).collect(Collectors.toList());
2.1.2 distinct去重
返回一个元素各异的流(根据流所生成元素的hashCode和Equals方法实现)
List numbers=Arrays.asList(1,1,2,2,3,4);
List collect=numbers.stream().distinct().collect(Collectors.toList());
2.1.3 sorted 排序
对流中的数据进行排序,可以用自然序或Comparator接口定义排序的规则,Comparator可以用lanbada表达式来初始化
List integers=Arrays.asList(1,9,8,3,4);
//排序默认为顺序
List sorted=integers.stream().sorted().collect(Collectors.toList());
//逆序
List reverseSorted
=integers.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
//使用lambada表达式排序
List userList
=userList.stream().sorted(Comparator.Comparing(User::getAge)).collect(Collectors.toList());
//集合简写方式
userList.sort((o1,o2)->{return o1.getAge()-o2.getAge();
});
//java 7的排序,顺序
userList.sort(new Comparator(){
@Override
Public int compare(User o1,User o2){
return o1.getAge().compareTo(o2.getAge());
}
})
2.1.4 Limit 截取
该方法返回一个不超过给定长度的流
List collect=integers.stream().limit(5).collect(Collectors.toList());
2.1.5 skip舍弃
该方法返回一个舍弃前面n个元素的流
List collect=integers.stream().skip(5).collect(Collectors.toList());
2.1.6 map,flatMap 归纳
该方法会接受一个函数作为参数,这个函数会被应用到每个元素上,并将其映射成一个新的元素。就是根据指定函数获取流中每个元素的数据,并重新组合成一个新的额元素。
List collect=UserList.Stream().map(User::getName).collect(Collectors.toList());
flatMap 把流中的层级结构扁平化,就是将最底层元素抽取出来放在一起。
Stream<List> s=Stream.of(
Arrays.asList(1),Arrays.asList(2),Arrays.asList(3)
);
Stream collect=s.flatMap(e->e.stream());
2.1.7 peek 插入执行动作
在流的每个元素恢复运行之前,插入执行一个动作。
List numbers =Arrays.asList(2,3,4,5);
List result
=numbers.stream().peek(x->System.out.println(x)).map(x->x+17).peek(x->System.out.println(x)).colllect(Collectors.toList());
2.1.8 collect 收集
collect是将最终stream中的数据收集起来,最终生成一个list、set或map。
List userList=User.getUserList();
//list
List collect=userList.stream().limit(10).collect(Collectors.toList());
//set
List collect1=userList.stream().limit(10).collect(Collectors.toSet());
//map
List<Long,String> collect2
=userList.stream().collect(Collectors.toMap(User::getId,User::getName));
2.2终止操作
- 循环 forEach
- 计算 min,max,count,average
- 匹配 anyMatch,allMatch,noneMatch,findFirst,findAny
- 汇聚 reduce
- 收集器 collect
2.3查找和匹配
2.3.1 anyMacth
流中是否有一个元素匹配到,返回boolean值。
boolean b=userList.stream().anyMatch(User::isMan);
2.3.2 allMatch
流中的元素是否全部匹配,返回boolean值
Boolean b=userList.stream().allMatch(e-> e.getAge<18);
2.3.3 noneMatch
流中没有任何元素匹配,返回boolean值
Boolean b=userList.stream().noneMatch(e-> e.getAge>60);
2.3.4 findAny
返回当前流中的任意元素
Optional any=userList.stream().findAny();
2.3.5 findFirst
找到想要的第一个元素
Optional user=userList.stream().filter(User::isMan).findFirst();
2.4 规约reduce
此类查询需要将流中所有元素反复结合起来,得到一个值,比如Integer值
2.4.1 元素求和
List integers=Arrays.asList(1,2,3,6,8);
//求list中的和,以0为基数
Integer reduce=integers.stream().reduce(0,(a,b)->a+b);
//Integer的静态方法
Int sum=integers.stream().reduce(Integer::sum);
2.4.2 最大值和最小值
//最小值
Optional min=integers.stream().reduce(Integer::min);
//最大值
Optional max=integers.stream().reduce(Integer::max);
2.5 Collectors收集器
2.5.1 查找流中的最大值,最小值 minBy,maxBy
//创建一个Comparator比较
Comparator userComparator=Comparator.compringInt(User::getAge);
//maxBy选出最大值
Optional collect=userList.stream().collect(Collectors.maxBy(userComparator));
//minBy选出最小值
Optional collect=userList.stream().collect(Collectors.minBy(userComparator));
2.5.2 summingInt 汇总
把对象映射成求和所需的int函数,返回一个收集器
int collect=userList.stream().collect(Collectors.summingInt(User::getAge));
2.5.3 averagingInt 平均数
Double collect=userList.stream().collect(Collectros.averagingInt(User::getAge))
2.5.4 joining 连接字符串
String collect=userList.stream().map(User::getName).collect(Collectors.joining());
//字符串连接,加分界符,
String collect=userList.stream().map(User::getName).collect(Collectors.joining(“,”));
2.5.5 counting 得到流中的总数
long l=userList.stream().collect(Collectors.counting());
2.6 groupingBy 分组
Map<Integer,List> map
=userList.stream().collect(Collectors.groupingBy(User::getType));
//按年龄分青年,中年,老年
Map<String,List> map=userList.stream().collect(Collectors.groupingBy(user->{
If(user.getAge()<18){
return “青年”;
}else if(user.getAge()<50){
return “中年”;
}else{
return “老年”;
}
}));
2.6.2 多级分组,先通过类型,在通过年龄分组
Map<Integer,Map<String,List>> collect
=userList.stream().collect(Collectors.groupingBy(User::getType,Collectors.groupingBy(e->{
if(e.getAge()<18){
return “青年”;
}else if(e.getAge()<50){
return “中年”;
}else{
return “老年”;
}
})));
2.6.3 按子组收集数据
例如,每个类型的人有多少个
Map<Integer,Long> collect=userList.stream().collect(Collectors.groupingBy(User::getType,counting()));
2.7 一些流操作
2.7.1 流转换为其他数据结构
//转成Array
String[] array=stream.toArray(String[]::new);
//转成collection
List list=stream.collect(Collectors.toList());
//转成string
String str=stream.collect(Collectors.joining(“,”));
2.7.2 转换大写
List out=wordList.stream().map(String::toUpperCase).collect(Collectros.toList());
2.7.3 平方数
List numList=Arrays.asList(1,2,3,4);
List num=numList.stream().map(i->i*i).collect(Collectors.toList());
2.7.4 forEach 循环
forEach 不能修改自己包含的本地变量值,也不能用 break/return 之类的关键字提前结束循环。
打印姓名
userList.stream().forEach(e->System.out.println(e.getName()));
2.7.5 List->Map (k1,k2)->k1 当有相同的key存在时,取已存在的key
Map<long,User> map
=userList.stream().collect(Collectors.toMap(User::getId,e->e,(k1,k2)->k1));
2.7.6 Array->List
List list=Stream.of(arrays).collect(Collectors.toList());
2.7.7 List->Array
String[] array=list.stream().toArray(String[]::new)
2.7.8 removeIf移除,将满足条件的内容移除掉
3. 并行流
并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。这样可以自动把给定的工作负荷分配多核处理器的所有内核处理。
3.1将顺序流转为并行流
顺序流转换成并行流,可以让求和并行运算
Stream s=Stream.iterate(1L,i->i+1).limit(1000);
Long sum=s.parallel().reduce(0L,Long::sum);
Stream在内部分成了几块。因此可以对不同的块独立并行归纳操作,同一个归纳操作会将各个子流的归纳结果合并起来,得到整个原始流的归纳结果。
对并行流调用sequenial方法就可以变成顺序流。
并行内部流默认的线程池 ForkJoinPool,它默认的线程数量就是处理器的数量。