深入浅出java8 stream流操作,带案例演示(Map集合)



基本介绍:

关于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;
     });

在数据量小的时候,我们一般不会使用并行流。 大数据量的时候,并行流所带来的性能优化就是显而易见了!

好了 基本已经讲完,欢迎大家评论区指出不足,一起学习进步!
大家看完了点个赞,码字不容易啊。。。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易柏州Innovation

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值