You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java 8 Stream对List<Banana>按名称分组并求和重量与价格

没问题,这事儿用Java 8+的Stream API就能轻松搞定,正好适配这种分组聚合的场景。我给你写几种实现方式,从兼容Java 8的基础写法到Java 12+的简洁优化版,再拆解开讲清楚每一步:

第一步:定义聚合结果类

首先我们需要一个类来存储分组后的聚合数据,这样返回的结构更清晰,比用Map或数组可读性强太多:

class BananaSummary {
    private String name;
    private Long totalWeight;
    private Long totalPrice;

    // 构造器
    public BananaSummary(String name, Long totalWeight, Long totalPrice) {
        this.name = name;
        this.totalWeight = totalWeight;
        this.totalPrice = totalPrice;
    }

    // Getter方法(按需添加)
    public String getName() { return name; }
    public Long getTotalWeight() { return totalWeight; }
    public Long getTotalPrice() { return totalPrice; }

    // 重写toString方便打印结果
    @Override
    public String toString() {
        return "BananaSummary{" +
                "name='" + name + '\'' +
                ", totalWeight=" + totalWeight +
                ", totalPrice=" + totalPrice +
                '}';
    }
}

方式一:Java 8兼容的直观写法

这种写法分两步:先按名称分组,再对每个分组单独求和,逻辑清晰,新手也能一眼看懂:

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

public class BananaGroupingDemo {
    public static void main(String[] args) {
        // 初始化你的香蕉集合
        List<Banana> bananas = List.of(
                new Banana("banana1", 10L, 20L),
                new Banana("banana1", 10L, 20L),
                new Banana("banana1", 10L, 20L),
                new Banana("banana2", 20L, 30L),
                new Banana("banana2", 30L, 30L),
                new Banana("banana3", 50L, 40L)
        );

        // 1. 先按香蕉名称分组,得到每个名称对应的香蕉列表
        Map<String, List<Banana>> groupedBananas = bananas.stream()
                .collect(Collectors.groupingBy(Banana::getName));

        // 2. 遍历分组,对每个组的weight和price分别求和,封装成BananaSummary
        List<BananaSummary> summaryList = groupedBananas.entrySet().stream()
                .map(entry -> {
                    String bananaName = entry.getKey();
                    // 求和总重量
                    Long totalWeight = entry.getValue().stream()
                            .mapToLong(Banana::getWeight)
                            .sum();
                    // 求和总价格
                    Long totalPrice = entry.getValue().stream()
                            .mapToLong(Banana::getPrice)
                            .sum();
                    return new BananaSummary(bananaName, totalWeight, totalPrice);
                })
                .collect(Collectors.toList());

        // 打印结果
        summaryList.forEach(System.out::println);
    }
}

方式二:Java 8的流式聚合写法(一步到位)

如果想在分组的同时完成聚合,可以用Collectors.reducing来实现,省去中间的Map存储:

Map<String, BananaSummary> groupedResult = bananas.stream()
        .collect(Collectors.groupingBy(
                Banana::getName, // 分组键:香蕉名称
                Collectors.reducing(
                        // 初始值:空的聚合对象
                        new BananaSummary("", 0L, 0L),
                        // 累加逻辑:把当前香蕉的weight和price加到聚合对象上
                        (summary, banana) -> new BananaSummary(
                                banana.getName(),
                                summary.getTotalWeight() + banana.getWeight(),
                                summary.getTotalPrice() + banana.getPrice()
                        ),
                        // 合并逻辑(多线程并行流时需要,单线程可以忽略)
                        (summary1, summary2) -> new BananaSummary(
                                summary1.getName(),
                                summary1.getTotalWeight() + summary2.getTotalWeight(),
                                summary1.getTotalPrice() + summary2.getTotalPrice()
                        )
                )
        ));

// 转换为List方便查看
List<BananaSummary> summaryList = new ArrayList<>(groupedResult.values());

方式三:Java 12+的简洁优化写法(用Teeing收集器)

Java 12引入的Collectors.teeing可以同时执行两个独立的收集操作,然后合并结果,处理这种多字段求和的场景特别顺手:

List<BananaSummary> summaryList = bananas.stream()
        .collect(Collectors.groupingBy(Banana::getName))
        .entrySet()
        .stream()
        .map(entry -> {
            String name = entry.getKey();
            // 同时对weight和price求和,然后合并成BananaSummary
            return entry.getValue().stream()
                    .collect(Collectors.teeing(
                            Collectors.summingLong(Banana::getWeight), // 第一个收集器:求重量总和
                            Collectors.summingLong(Banana::getPrice),  // 第二个收集器:求价格总和
                            (totalWeight, totalPrice) -> new BananaSummary(name, totalWeight, totalPrice) // 合并结果
                    ));
        })
        .collect(Collectors.toList());

最终输出结果

不管用哪种方式,最终都会得到如下聚合结果:

BananaSummary{name='banana1', totalWeight=30, totalPrice=60}
BananaSummary{name='banana2', totalWeight=50, totalPrice=60}
BananaSummary{name='banana3', totalWeight=50, totalPrice=40}

内容的提问来源于stack exchange,提问作者CR7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:17:35