深入浅出java8 stream流操作
基本介绍:
关于stream的基本原理这里不介绍了。我之前找到这篇博客,写得很好。
java8中stream原理概述
无状态:指元素的处理不受之前元素的影响;
有状态:指该操作只有拿到所有元素之后才能继续下去。
非短路操作:指必须处理所有元素才能得到最终结果;
短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
案例演示(串行流):
初始化List:
static List<Map<String,Object>> list = new ArrayList();
static {
int i = 10;
while (i>0){
Map<String,Object> map = new HashMap<>();
map.put("name","张三"+i+"号");
map.put("age",i);
list.add(map);
i--;
}
}
生成包含10个Map元素的List集合,每个元素代表一个人员。包含”姓名“,”年龄“。
filter过滤:
过滤掉集合中name为”张三1号“的元素。
List<Map<String, Object>> res = list.stream()
//遍历元素,如果元素的name不等于张三1号,就加入到新集合中
.filter(e->!e.get("name").equals("张三1号"))
.collect(Collectors.toList());
但是如果是多条件怎么办?比如现在集合中有两个元素的name是”张三1号“,age分别是1和2,现在我要过滤掉name是”张三1号“并且age是2的元素
Map<String,Object> map = new HashMap<>();
map.put("name","张三1号");
map.put("age",2);;
list.add(map);
List<Map<String, Object>> res = list.stream()
.filter(e->((e.get("name").equals("张三1号") && (int)e.get("age") != 2)) || !e.get("name").equals("张三1号"))
.collect(Collectors.toList());
上面的例子看起来有点绕,其实你只要记住一点:
filter({条件}) ,条件返回true的话说明通过了判断,会保留下来。条件返回false,说明被拦截,不会保留下来
distinct去重:
现在集合中有两个 name:张三1号,age:1 。 通过distinct去重
Map<String,Object> map = new HashMap<>();
map.put("name","张三1号");
map.put("age",1);;
list.add(map);
List<Map<String, Object>> res = list.stream().distinct().collect(Collectors.toList());
map(映射,重构。对原集合的元素进行操作,生成一个新集合):
现在将集合中所有元素的age+1,并添加一个属性sex:“男”。
List<Map<String, Object>> res = list.stream().map(e->{
e.put("age",(int)e.get("age")+1);
e.put("sex","男");
return e;
}).collect(Collectors.toList());
peek(类似于map。映射,重构。对原集合的元素进行操作):
和map的区别在于,peek是直接对原集合进行操作,不会生成新集合。
list.stream().peek(e->{
e.put("age",(int)e.get("age")+1);
e.put("sex","男");
})
max/min/count(聚合)
得到集合中age最大的元素(max)
Optional<Map<String, Object>> res = list.stream().max((o1, o2) -> {
Integer a = (Integer)o1.get("age");
Integer b = (Integer)o2.get("age");
return a.compareTo(b);
});
这里需要说明一下。 可以看到我们的返回值是Optional。 因为list.stream()之后,所有的元素都变成了流,每一个流是Optional类型的数据,所以返回Optional类型。
得到集合中age最小的元素(min)
Optional<Map<String, Object>> res = list.stream().min((o1, o2) -> {
Integer a = (Integer)o1.get("age");
Integer b = (Integer)o2.get("age");
return a.compareTo(b);
});
得到集合中age大于5的元素的个数(count)
long res = list.stream().filter(e->(int)e.get("age")>5).count();
reduce(计算,实现对集合求和、求乘积和求最值操作)
求出集合中所有元素的age的总和
Optional<Map<String, Object>> res = list.stream().reduce((e, f)->{
Integer a = (Integer)e.get("age");
Integer b = (Integer)f.get("age");
Map result = new HashMap();
result.put("age",a+b);
return result;
});
partitioningBy/groupingBy(分组)
partitioningBy:根据自定义的条件进行分组,如:年龄>5。
groupingBy:根据集合元素的属性进行分组,不需要自定义条件。如:sex,类似sql里的group by
开始之前,我们先将原始集合改变一下。现在集合是这样的:
将集合按是否age>5分为两组
Map<Boolean, List<PersonEntity>> res = personEntityList.stream()
.collect(Collectors.partitioningBy(e->e.getAge()>5));
返回一个Map集合,键是一个boolean值,为true,对应的值就是age>5的集合。false则对应其他的集合。
将集合按地区分组
Map<Object, List<PersonEntity>> res2 = personEntityList.stream()
.collect(Collectors.groupingBy(e-> e.getArea()));
结果是什么样的呢?我复制出来看看
{
美国=[{name='张五', age=3, area='美国'}, {name='张六', age=4, area='美国'}],
法国=[{name='张九', age=7, area='法国'}],
中国=[{name='张三', age=1, area='中国'}, {name='张四', age=2, area='中国'}],
加拿大=[{name='张十一', age=9, area='加拿大'}, {name='张十二', age=10, area='加拿大'}],
日本=[{name='张十', age=8, area='日本'}],
英国=[{name='张七', age=5, area='英国'}, {name='张八', age=6, area='英国'}]
}
将集合先按地区分组,然后再按age分组
Map<Object, Map<Object, List<PersonEntity>>> res3 = personEntityList.stream().collect(Collectors.groupingBy(e->e.getArea(),Collectors.groupingBy(a->a.getAge())));
看看结果
{
美国={3=[{name='张五', age=3, area='美国'}], 4=[{name='张六', age=4, area='美国'}]},
法国={7=[{name='张九', age=7, area='法国'}]},
中国={1=[{name='张三', age=1, area='中国'}], 2=[{name='张四', age=2, area='中国'}]},
加拿大={9=[{name='张十一', age=9, area='加拿大'}], 10=[{name='张十二', age=10, area='加拿大'}]},
日本={8=[{name='张十', age=8, area='日本'}]},
英国={5=[{name='张七', age=5, area='英国'}], 6=[{name='张八', age=6, area='英国'}]}
}
joining(结合)
提取集合的所有元素中的name组成规定的字符串,如”张三@张四@张五“
String res = personEntityList.stream()
.map(e->e.getName()).collect(Collectors.joining("@"));
sorted(排序)
将集合中的元素按照age降序排列
List<PersonEntity> res = personEntityList.stream()
.sorted(Comparator.comparing(PersonEntity::getAge)
.reversed()).collect(Collectors.toList());
先按age降序,再按area升序
List<PersonEntity> res = personEntityList.stream()
.sorted(Comparator.comparing(PersonEntity::getAge).reversed()
.thenComparing(PersonEntity::getArea)).collect(Collectors.toList());
自定义排序
List<PersonEntity> res = personEntityList.stream().sorted((x, y)->{
if(xxxxx){
return xxxxx
}else {
return xxxxx
}
}).collect(Collectors.toList());
concat(合并)
将两个集合合并为一个集合
List list1 = new ArrayList(Arrays.asList("a","b"));
List list2 = new ArrayList(Arrays.asList("c","d"));
List res = (List) Stream.concat(list1.stream(),list2.stream())
.collect(Collectors.toList());
案例演示(并行流):
并行流有两种创建方式
1.list.stream().parallel() 将串行流转成并行
2.list.parallelStream() 直接创建并行流
那么什么是并行流,这里一句话说清楚。 就是将数据分为多份,分别在不同的线程中同时运行业务逻辑。大大减少了运行时间。
我们现在重复上面的一个例子,用并行流算出集合中所有元素的age的和。
Optional<PersonEntity> res = personEntityList.parallelStream().reduce((e, f)->{
f.setAge(f.getAge()+e.getAge());
return f;
});
在数据量小的时候,我们一般不会使用并行流。 大数据量的时候,并行流所带来的性能优化就是显而易见了!
好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!
大家看完了点个赞,码字不容易啊。。。