使用stream.distinct校验Integer列表重复值时误触发BadRequestException的问题排查
问题分析与解决方案
看起来你遇到的问题是新增的重复校验逻辑总是触发,无论positionsPoste列表中是否存在重复值。我们来一步步拆解问题并解决它:
可能的原因
你的校验逻辑stream().distinct().count() != size()本身逻辑是正确的,但出现这种异常情况通常有以下几种可能:
- 列表中存在
null值:如果positionsPoste里有多个null,distinct()会将所有null视为同一个值,导致count()结果小于列表size(),触发异常。而你可能没注意到前端提交时传入了null值(比如表单输入框未填写)。 - 前端提交的列表存在隐性重复:比如前端传入的字符串数值(如"01"和"1")被Spring MVC自动转换为相同的
Integer值,导致你视觉上认为没有重复,但实际是重复的。 - 流操作的类型对比细节:
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
相关产品推荐
相关产品推荐

