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

如何用Java 8 Stream按ProductId分组并获取最大ProductTransactionId

问题需求

我有一个ProductTransaction列表,需要找出每个ProductId对应的最大(最新)productTransactionId的交易记录。要求按ProductId分组,依据productTransactionId排序,示例最终结果为List<Integer> (2, 5, 9)。当前使用Java 8,想用Stream和Filter实现,现有方案比较冗长,希望得到更简洁或性能更优的写法。

实体类定义

@Data
public class ProductTransaction {
    private int productTransactionId;
    private int productId;
    private Date saleDate;
    private BigDecimal amount;
}

示例数据

ProductTransactionIdProductIdSaleDateAmount
113/2/20195
214/1/20199
324/1/20192
428/21/20193
528/21/20194
6310/1/20192
7310/3/20195
8310/3/20197
9310/3/20198

注意:忽略SaleDate字段,仅按ProductTransactionId排序;输入数据不一定有序。

现有冗长实现

Set<Long> finalProductTransactionIds = new HashSet<>();
    
Set<Long> distinctProductIds =  productTransactions.stream()
        .map(ProductTransaction::getProductId)
        .collect(Collectors.toSet());

for (Long productId: distinctProductIds) {
    Long productTransactionId = productTransactions.stream()
            .filter(x -> x.getProductId() == productId)
            .sorted(Comparator.comparing(ProductTransaction::getProductTransactionId)
            .reversed())
            .collect(Collectors.toList()).get(0).getProductTransactionId();
    finalProductTransactionIds.add(productTransactionId);
}

优化方案

方案1:分组取最大值(直观清晰)

通过一次流操作完成分组和最大值筛选,避免多次遍历列表:

List<Integer> maxTransactionIds = productTransactions.stream()
        // 按ProductId分组,每组保留transactionId最大的记录
        .collect(Collectors.groupingBy(
                ProductTransaction::getProductId,
                Collectors.maxBy(Comparator.comparingInt(ProductTransaction::getProductTransactionId))
        ))
        .values()
        .stream()
        .filter(Optional::isPresent)
        .map(Optional::get)
        .map(ProductTransaction::getProductTransactionId)
        .collect(Collectors.toList());

优势:

  • 仅遍历原始列表1次,性能远优于原方案(原方案遍历次数=1+不同ProductId数量)
  • 代码逻辑清晰,符合Stream API链式风格

方案2:直接映射去重合并(最简洁高效)

如果只需要最大交易ID集合,用toMap的合并函数直接生成结果:

// 若需要List则用 new ArrayList<>(...) 包裹结果
Set<Integer> maxTransactionIds = productTransactions.stream()
        .collect(Collectors.toMap(
                ProductTransaction::getProductId,
                ProductTransaction::getProductTransactionId,
                // 同一ProductId下保留较大的transactionId
                (existing, newVal) -> Math.max(existing, newVal)
        ))
        .values();

优势:

  • 代码最紧凑,无多余中间操作
  • 同样仅遍历1次列表,性能最优
  • 结果自动去重,直接得到每个ProductId对应最大交易ID

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:25:13