Stream分组掌握这个你代码可以少些一半了

Posted 沛沛老爹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Stream分组掌握这个你代码可以少些一半了相关的知识,希望对你有一定的参考价值。

背景

查询的List列表中的某列的值,需要根据另外一个对象列表的List中的某个属性来统计。

例如现在存在A对象ClassA和B对象StudentB。

需要对查询出来的List<ClassA>列表中展示StudentB中的用户特长属性列表。用户特长信息存在与StudentAttrC中。

他们的关系如下

代码如下


@Data
public class ClassA
    private Integer id; 
    
    //人数
    private Integer count;
    ...
   
@Data
public class StudentB
    private Integer id;
    
    private Integer classAId;
    
    private Integer amount;
    ...

@Data
public class StudentAttrC
    private Integer id;
    
    private Integer StudentBId;

    private BigDecimal money;
    
    ...
 

现在需要在List<ClassA>中,需要将每个班的人数统计展示出来。

因为用到的是分布式系统和多库的开发模式,要求不能进行连表查询。

(先不考虑ClassAttr中的统计条件了,估计这会儿有的小伙伴们头有点大。。。。)

好吧,立马安排

解决思路

推荐使用Stream中的groupBy和sum来解决

可以看下下面的这个例子,统计列表中的所有指定性别的用户年纪之和。

package com.test;

import lombok.Data;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Test 
    public static void main(String[] args) 
        List<TestA> list =initData();

        Map<Integer,Integer> map =list.stream().collect(Collectors.groupingBy(TestA::getSex,Collectors.summingInt(TestA::getAge)));
        for(Map.Entry<Integer,Integer> entry:map.entrySet()) 
            System.out.println("sex:"+entry.getKey()+"  ageSum:"+entry.getValue());
        
    

    public static  List<ClassA> initData()
        List<TestA> list = new ArrayList<>();
        for(int i=0;i<5;i++)
            TestA a = new TestA();
            a.setAge(i);
            a.setSex(1);
            a.setName("测试"+i);
            list.add(a);
            TestA b = new TestA();
            BeanUtils.copyProperties(a,b);
            b.setSex(2);
            b.setAge(a.getAge()*2);
            list.add(b);
        
        return  list;
    
 

@Data
class TestA
    private  Integer age;
    private  Integer sex;
    private  String name;

我们可以看到根据性别不同,

最后统计出来的结果为一个map,里面根据sex分组了两条不同的数据。

整个代码中,做统计只用了一行代码

  Map<Integer,Integer> map =list.stream()
     .collect(Collectors.groupingBy(TestA::getSex,
      Collectors.summingInt(TestA::getAge)));

在这里面,我们使用了groupingBy来进行分组。

使用了summingInt来进行统计。

这样一行代码解决了我们的问题。同时还用到了map的特性。

优越性总结

开发效能

代码写的多,中间容易出差错。

同时写的多的话,后续维护也比较麻烦,特别是嵌套里面的逻辑比较傲娇的那种。

代码可读性

如果是常规的统计的话,我们需要将所有的数据拿出来,然后使用循环一行行的匹配。

 这样可读性比较糙,使用map的方式一目了然。

代码性能

用for循环的话,走的是O(n)的方式。

用map,使用的是O(1)。所以是没有可比性的。

同时,如果你遇到那种假程序员,往里面嵌套读取数据库,那就是一场人间灾难了。

好了,根据上面的例子,你就可以尝试解决提出的那个问题了,再嵌套ClassAttrC也不在话下了。

以上是关于Stream分组掌握这个你代码可以少些一半了的主要内容,如果未能解决你的问题,请参考以下文章

JDK8对List进行分组操作(stream的groupby)

一文掌握stream,让你的代码提高一个境界

掌握统计学,做选择时的纠结少一半!

Stream API

深度掌握 Java Stream 流操作,让你的代码高出一个逼格!

Java 8 的Stream流那么强大!