Java中的Collectors类的groupingBy()方法用于按某些属性对对象进行分组并将结果存储在Map实例中。
当我我们想利用它的特性,我们需要指定一个属性来执行分组。此方法提供的函数类似于SQL的GROUP BY子句。

public static Collector<T, ?, Map<K, List>> groupingBy(Function classifier)

类型参数:此方法采用两个类型参数:

T-这是输入元素的类型。
K-这是要转换的输入元素的类型。
参数:此方法接受两个强制性参数:

Function-这是要应用于输入元素的属性。
Classifier-它用于将输入元素映射到目标映射中。
返回值:它返回一个Collector作为Map。

Collectors.groupingBy根据一个或多个属性对集合中的项目进行分组

1、测试数据准备

1.1、首先,创建一个实体生产实体类,用于模拟测试数据

@Data
public class Product {
    private Long id;
    private Integer num;
    private BigDecimal price;
    private String name;
    private String category;
    private Integer size;
    public Product(Long id, Integer num, BigDecimal price, String name, String category, Integer size) {
        this.id = id;
        this.num = num;
        this.price = price;
        this.name = name;
        this.category = category;
        this.size = size;

1.2、创建测试类

代码结构如下:

构造测试数据:

  Product prod1 = new Product(1L, 1, new BigDecimal("15.5"), "面包", "零食",1);
   Product prod2 = new Product(2L, 2, new BigDecimal("20"), "饼干", "零食",1);
   Product prod3 = new Product(3L, 3, new BigDecimal("30"), "月饼", "零食",2);
   Product prod4 = new Product(4L, 3, new BigDecimal("10"), "青岛啤酒", "啤酒",1);
   Product prod5 = new Product(5L, 10, new BigDecimal("15"), "百威啤酒", "啤酒",1);
   Product prod6 = new Product(6L, 7, new BigDecimal("25"), "百威啤酒", "啤酒",1);
   Product prod7 = new Product(7L, 1, new BigDecimal("15.4"), "面包", "零食",1);
   Product prod8 = new Product(8L, 7, new BigDecimal("25.5"), "百威啤酒", "啤酒",2);
   List<Product> prodList = List.of(prod1, prod2, prod3, prod4, prod5, prod6,prod7,prod8);

2、开始测试

2.1、按照类别分组

    Map<String, List<Product>> map1 = prodList.stream().collect(Collectors.groupingBy(Product::getCategory));
    Set<Map.Entry<String, List<Product>>> entries1 = map1.entrySet();
    for (Map.Entry<String, List<Product>> entry : entries1) {
      System.out.println(entry);
==============================按照类别分组=============================================
啤酒=[Product{id=4, num=3, price=10, name='青岛啤酒', category='啤酒', size=1}, Product{id=5, num=10, price=15, name='百威啤酒', category='啤酒', size=1}, Product{id=6, num=7, price=25, name='百威啤酒', category='啤酒', size=1}, Product{id=8, num=7, price=25.5, name='百威啤酒', category='啤酒', size=2}]
零食=[Product{id=1, num=1, price=15.5, name='面包', category='零食', size=1}, Product{id=2, num=2, price=20, name='饼干', category='零食', size=1}, Product{id=3, num=3, price=30, name='月饼', category='零食', size=2}, Product{id=7, num=1, price=15.4, name='面包', category='零食', size=1}]

2.2、按照多个属性拼接分组(类别+名称)

Map<String, List<Product>> map2 = prodList.stream()
            .collect(Collectors.groupingBy(new Function<Product, String>() {
                                             @Override
                                             public String apply(Product product) {
                                               return product.getCategory() + "_" + product.getName();
    Set<Map.Entry<String, List<Product>>> entries2 = map2.entrySet();
    for (Map.Entry<String, List<Product>> entry : entries2) {
      System.out.println(entry);
==============================按照多个属性拼接分组(类别——名称)=============================================
零食_月饼=[Product{id=3, num=3, price=30, name='月饼', category='零食', size=2}]
零食_面包=[Product{id=1, num=1, price=15.5, name='面包', category='零食', size=1}, Product{id=7, num=1, price=15.4, name='面包', category='零食', size=1}]
啤酒_百威啤酒=[Product{id=5, num=10, price=15, name='百威啤酒', category='啤酒', size=1}, Product{id=6, num=7, price=25, name='百威啤酒', category='啤酒', size=1}, Product{id=8, num=7, price=25.5, name='百威啤酒', category='啤酒', size=2}]
啤酒_青岛啤酒=[Product{id=4, num=3, price=10, name='青岛啤酒', category='啤酒', size=1}]
零食_饼干=[Product{id=2, num=2, price=20, name='饼干', category='零食', size=1}]

2.3、按照num数值的大小来

    Map<String, List<Product>> map3 = prodList.stream().collect(Collectors.groupingBy(item -> {
      if (item.getNum() > 3) {
        return "num大于3";
      } else if (item.getNum() < 3) {
        return "num小于3";
      } else {
        return "num等于3";
    Set<Map.Entry<String, List<Product>>> entries3 = map3.entrySet();
    for (Map.Entry<String, List<Product>> entry : entries3) {
      System.out.println(entry);
===========================按照num数值的大小来================================================
num小于3=[Product{id=1, num=1, price=15.5, name='面包', category='零食', size=1}, Product{id=2, num=2, price=20, name='饼干', category='零食', size=1}, Product{id=7, num=1, price=15.4, name='面包', category='零食', size=1}]
num等于3=[Product{id=3, num=3, price=30, name='月饼', category='零食', size=2}, Product{id=4, num=3, price=10, name='青岛啤酒', category='啤酒', size=1}]
num大于3=[Product{id=5, num=10, price=15, name='百威啤酒', category='啤酒', size=1}, Product{id=6, num=7, price=25, name='百威啤酒', category='啤酒', size=1}, Product{id=8, num=7, price=25.5, name='百威啤酒', category='啤酒', size=2}]

2.4、先按照类别分组,再按照num分组

 Map<String, Map<String, List<Product>>> map4 = prodList.stream()
            .collect(Collectors.groupingBy(Product::getCategory, Collectors.groupingBy(item -> {
              if (item.getNum() >= 8) {
                return "num大于等于8";
              } else {
                return "num小于8";
            })));
    Set<Map.Entry<String, Map<String, List<Product>>>> entries4 = map4.entrySet();
    for (Map.Entry<String, Map<String, List<Product>>> entry : entries4) {
      System.out.println(entry);
===========================先按照类别分组,再按照num分组================================================
啤酒={num小于8=[Product{id=4, num=3, price=10, name='青岛啤酒', category='啤酒', size=1}, Product{id=6, num=7, price=25, name='百威啤酒', category='啤酒', size=1}, Product{id=8, num=7, price=25.5, name='百威啤酒', category='啤酒', size=2}], num大于等于8=[Product{id=5, num=10, price=15, name='百威啤酒', category='啤酒', size=1}]}
零食={num小于8=[Product{id=1, num=1, price=15.5, name='面包', category='零食', size=1}, Product{id=2, num=2, price=20, name='饼干', category='零食', size=1}, Product{id=3, num=3, price=30, name='月饼', category='零食', size=2}, Product{id=7, num=1, price=15.4, name='面包', category='零食', size=1}]}

2.5、先按照类别分组,再聚合求总数

Map<String, Long> map5 = prodList.stream()
            .collect(Collectors.groupingBy(Product::getCategory, Collectors.counting()));
    Set<String> strings5 = map5.keySet();
    for (String s : strings5) {
      System.out.println(s + "---" + "总数:" + map5.get(s));
===========================先按照类别分组,再聚合求总数================================================
啤酒---总数:4
零食---总数:4

2.6、先按照类别分组,再聚合运算(把num相加)

Map<String, Integer> map6 = prodList.stream()
            .collect(Collectors.groupingBy(Product::getCategory, Collectors.summingInt(Product::getNum)));
    Set<String> strings6 = map6.keySet();
    for (String s : strings6) {
      System.out.println(s + "---" + "num相加后:" + map6.get(s));
===========================先按照类别分组,再聚合运算(把num相加)================================================
啤酒---num相加后:27
零食---num相加后:7