在工作中会遇到一些List 需要按照 多个字段分组,其实可以这样写。
实体类

//这里的注解是省的写get set 等方法 不过多解释
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    //订单区域
    private String address;
    //订单类型
    private String type;
    //收款金额
    private int price;
    //退款金额
    private int refund;
}

Demo

public class Test {
    public static void main(String[] args) {
		//这里模拟数据
        List<Order> orders = Arrays.asList( new Order("安徽","内部订单",100,0),
                                            new Order("安徽","内部订单",200,50),
                                            new Order("安徽","外部订单",100,100),

                                            new Order("河南","内部订单",100,0),
                                            new Order("河南","外部订单",300,0),
                                            new Order("河南","内部订单",200,100),

                                            new Order("河北","内部订单",100,0),
                                            new Order("河北","内部订单",100,0),
                                            new Order("河北","内部订单",100,0),

                                            new Order("江西","内部订单",100,50),
                                            new Order("江西","外部订单",100,100));
        //先输出一下原始数据
        System.out.println("分组之前的数据");
        orders.forEach(System.out :: println);
        System.out.println("分组之后的数据");
        //准备好数据之后,调用一下方法
        List<Order> ordersByGroup = groupByAddressAndType(orders);
        //输出一下分组之后的数据
        ordersByGroup.forEach(System.out :: println);
    }

    /**
     * 需求:
     *    按照地址,和订单类型 分组数据  并且 收款金额,和退款金额都要统计
     */
    public static List<Order> groupByAddressAndType(List<Order> orders) {
        //这个map 是用来统计收款金额的
        Map<String, IntSummaryStatistics> priceMap = orders.parallelStream()
                .collect(Collectors.groupingBy(
                        //这里按照getAddress 地址     getType 类型来作为分组的条件              最后想要统计的是交易金额
                        a -> a.getAddress() + "_" + a.getType(), Collectors.summarizingInt(a -> a.getPrice()))
                );
        //这个map 是用来统计退款金额的
        Map<String, IntSummaryStatistics> refundMap = orders.parallelStream()
                .collect(Collectors.groupingBy(
                        //这里按照getAddress 地址     getType 类型来作为分组的条件              最后想要统计的是交易金额
                        a -> a.getAddress() + "_" + a.getType(), Collectors.summarizingInt(a -> a.getRefund()))
                );
        orders.forEach(order -> {
            //这个获取map对应值
            long price = priceMap.get(order.getAddress() + "_" + order.getType()).getSum();
            long refund = refundMap.get(order.getAddress() + "_" + order.getType()).getSum();
            //这里把取出来的值 赋给order
            order.setPrice((int) price);
            order.setRefund((int) refund);
        });
        //最后返回
        return orders.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(
                () -> new TreeSet<>(
                        // 这里的规则和 上面分组的规则一样
                        Comparator.comparing(u -> u.getAddress() + "_" + u.getType())
                )), ArrayList::new));
    }
}

输出的结果如下

分组之前的数据
Order(address=安徽, type=内部订单, price=100, refund=0)
Order(address=安徽, type=内部订单, price=200, refund=50)
Order(address=安徽, type=外部订单, price=100, refund=100)
Order(address=河南, type=内部订单, price=100, refund=0)
Order(address=河南, type=外部订单, price=300, refund=0)
Order(address=河南, type=内部订单, price=200, refund=100)
Order(address=河北, type=内部订单, price=100, refund=0)
Order(address=河北, type=内部订单, price=100, refund=0)
Order(address=河北, type=内部订单, price=100, refund=0)
Order(address=江西, type=内部订单, price=100, refund=50)
Order(address=江西, type=外部订单, price=100, refund=100)
分组之后的数据
Order(address=安徽, type=内部订单, price=300, refund=50)
Order(address=安徽, type=外部订单, price=100, refund=100)
Order(address=江西, type=内部订单, price=100, refund=50)
Order(address=江西, type=外部订单, price=100, refund=100)
Order(address=河北, type=内部订单, price=300, refund=0)
Order(address=河南, type=内部订单, price=300, refund=100)
Order(address=河南, type=外部订单, price=300, refund=0)

分析数据,以安徽为例,
2个内部订单 收款金额price 分别为 100,200 分组合并后 应该为 300 退款金额 分别为 0,50 合并后为50
1个外部订单 收款金额price 分别为 100 分组合并后 应该为 100 退款金额 分别为 100 合并后为100
以此类推,数据都是正确的,不再逐个分析

此为List<对象> 的多分组
List<Map<String, Object>> 类型的多字段分组 也是如此类推,
如果2个字段分组还不能满足你的需求,

a -> a.getAddress() + "_" + a.getType() + "_" + a.getXXX() //后面多拼 几个字段
Map<String, IntSummaryStatistics> map //如果 要统计的数据更多,就多几个这个map