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

使用stream.distinct校验Integer列表重复值时误触发BadRequestException的问题排查

问题分析与解决方案

看起来你遇到的问题是新增的重复校验逻辑总是触发,无论positionsPoste列表中是否存在重复值。我们来一步步拆解问题并解决它:

可能的原因

你的校验逻辑stream().distinct().count() != size()本身逻辑是正确的,但出现这种异常情况通常有以下几种可能:

  1. 列表中存在null值:如果positionsPoste里有多个null,distinct()会将所有null视为同一个值,导致count()结果小于列表size(),触发异常。而你可能没注意到前端提交时传入了null值(比如表单输入框未填写)。
  2. 前端提交的列表存在隐性重复:比如前端传入的字符串数值(如"01"和"1")被Spring MVC自动转换为相同的Integer值,导致你视觉上认为没有重复,但实际是重复的。
  3. 流操作的类型对比细节:count()返回的是long类型,size()是int类型,虽然Java会自动转换,但在某些极端场景下可能出现非预期的对比结果(不过你的业务场景大概率不会遇到)。

解决方案

1. 替换校验逻辑为更直观的HashSet方式

用HashSet来判断重复会更直接,同时避免流操作的潜在问题:

List<Integer> positions = cheminementForm.getPositionsPoste();
if (new HashSet<>(positions).size() != positions.size()) {
    throw new BadRequestException("Cannot have same positions");
}

HashSet会自动基于equals去重,其size()与原列表size()对比能准确判断是否存在重复元素。

2. 添加日志排查实际数据

在校验前添加日志,打印positionsPoste的具体内容、长度和去重后的长度,这样就能明确触发异常的原因:

List<Integer> positions = cheminementForm.getPositionsPoste();
log.info("PositionsPoste content: {}", positions);
log.info("Original list size: {}", positions.size());
long distinctCount = positions.stream().distinct().count();
log.info("Distinct elements count: {}", distinctCount);
if (distinctCount != positions.size()) {
    throw new BadRequestException("Cannot have same positions");
}

通过日志你能清楚看到列表里是否有null、重复值,或者其他异常数据。

3. 修复循环中的NullPointerException隐患

你的循环里直接判断positionsPoste.get(i) < 0,如果元素是null会抛出NullPointerException,建议先判断null并修正异常提示:

for(int i=0; i<cheminementForm.getEtapes().size(); i++){
    Integer position = cheminementForm.getPositionsPoste().get(i);
    if(position == null || position < 0 ){
        throw new BadRequestException("Position cannot be null or negative");
    }
    cheminementEtapeList.add(CheminementEtape.builder()
            .cheminement(cheminement)
            .etape(cheminementForm.getEtapes().get(i))
            .positionPoste(position)
            .disable(false)
            .build());
}

4. 增强表单校验

虽然你的CheminementForm有@NotNull注解,但没有校验列表元素的非空和合法性,可以添加注解在请求绑定阶段就拦截非法数据:

@Data
public class CheminementForm {
    @NotNull(message = "{cheminement.form.name.notEmpty}")
    @Size(min=2, max=30)
    private String name;
    
    @NotNull(message = "{cheminementEtape.form.etape.notEmpty}")
    @NotEmpty(message = "{cheminementEtape.form.etape.notEmpty}")
    private List<Etape> etapes;
    
    @NotNull(message = "{cheminementEtape.form.positionPoste.notEmpty}")
    @NotEmpty(message = "{cheminementEtape.form.positionPoste.notEmpty}")
    @Positive(message = "{cheminementEtape.form.positionPoste.positive}")
    private List<Integer> positionsPoste;
}

这样Spring MVC会在请求进入服务层之前就校验列表不为空、元素为正整数,减少后续的异常处理逻辑。

总结

优先通过日志排查实际提交的数据,确认是否存在null或隐性重复值,然后替换校验逻辑为HashSet方式,同时修复代码中的潜在NPE问题,增强表单校验,这样就能解决你的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:07:34