Java Lambda嵌套循环中NoSuchElementException异常修复
迭代器抛出NoSuchElementException异常修复及代码优化
问题描述
执行代码中int uploadId = uploadLogIdIterator.next().getUploadLogId();语句时,抛出java.util.NoSuchElementException异常,需要修复该问题并优化整体代码逻辑。
原业务代码
public SomeEntity saveGeneratedPriceInstructions(List<SomeDTO> someDTOList, boolean force) { List<String> weekNames = PeriodsUtils.getWeekNames(someDTOList.get(0).getWeekName()); String codeToReturn = someDTOList.get(0).getCode(); Set<String> encounteredCode = new HashSet<>(); List<Integer> oldPIList = new ArrayList<>(); List<SomeEntity> uploadLogToSaveList = new ArrayList<>(); someDTOList.stream().map(SomeDTO::getCode).forEach(code -> { if (encounteredCode.contains(code)) return; else { encounteredCode.add(code); } SomeEntity oldPI = someRepository.findOneByCsuCodeEqualsAndWeekNumberEqualsAndApprovalStatusNotLikeOrderByUploadLogIdDesc( code, weekNames.get(0), APPROVED_STATUS); // 移除该注释如果不需要支持无补位的周号格式(如w1_2020) if (oldPI == null && weekNames.size() == 2) { oldPI = someRepository.findOneByCsuCodeEqualsAndWeekNumberEqualsAndApprovalStatusNotLikeOrderByUploadLogIdDesc( code, weekNames.get(1), APPROVED_STATUS); } if (oldPI != null) { oldPIList.add(oldPI.getUploadLogId()); } SomeEntity uploadLogToSave = new SomeEntity(code, weekNames.get(0)); uploadLogToSaveList.add(uploadLogToSave); }); someRepository.deleteAllByIdInBatch(oldPIList); List<SomeEntity> someEntityList = (List<SomeEntity>) someRepository.saveAllAndFlush(uploadLogToSaveList); System.out.println("size" + someEntityList.size()); Iterator<SomeEntity> uploadLogIdIterator = someEntityList.iterator(); someDTOList.stream().map(SomeDTO::getCode).forEach(code -> { int uploadId = uploadLogIdIterator.next().getUploadLogId(); someDTOList.stream().filter(someDTO -> someDTO.getCode().equals(code)).forEach(product -> { // 激活所有未激活的产品 if (!product.isActive()) { pricingProductService.activateProduct(Long.valueOf(product.getProductCode())); } product.setId(0); product.setUploadLogId(uploadId); Integer weekId = modelPiWeekService.saveModelPiWeekDtoRestful(product).getId(); getModelPiWeekDeltaDTOStream(product).forEach(period -> modelPiWeekDeltaService.saveModelPiWeekDeltaDtoRestful(weekId, period)); }); }); return someRepository.findOneByCsuCodeEqualsAndWeekNumberEqualsAndApprovalStatusEqualsOrderByUploadLogIdDesc( codeToReturn, weekNames.get(0), "C"); }
异常堆栈信息
java.util.NoSuchElementException: null at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1000) ~[na:na] at com.arcelormittal.ninasteel.nina_ui.service.ModelPiWeekUploadLogService.lambda$saveGeneratedPriceInstructions$5(ModelPiWeekUploadLogService.java:150) ~[classes/:na] at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[na:na] at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na] at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655) ~[na:na] at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na] at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na] at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[na:na] at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[na:na] at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na] at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) ~[na:na] at com.arcelormittal.ninasteel.nina_ui.service.ModelPiWeekUploadLogService.saveGeneratedPriceInstructions(ModelPiWeekUploadLogService.java:149) ~[classes/:na] at com.arcelormittal.ninasteel.nina_ui.service.ModelPiWeekUploadLogService$$FastClassBySpringCGLIB$$59a8179d.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar:5.3.20] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.20.jar:5.3.20] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.20.jar:5.3.20]
异常原因分析
核心问题是:
someEntityList的元素数量是去重后的code数量(通过encounteredCodeHashSet去重)- 但后续遍历的是
someDTOList.stream().map(SomeDTO::getCode),包含大量重复的code,遍历次数远大于someEntityList的元素数 - 迭代器的
next()调用次数超过了集合元素总量,导致抛出NoSuchElementException
修复及优化后的代码
核心修复点
用Map<String, Integer>存储code与对应uploadId的映射关系,替代迭代器,彻底避免迭代器耗尽问题。
完整优化代码
import org.springframework.util.CollectionUtils; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; public SomeEntity saveGeneratedPriceInstructions(List<SomeDTO> someDTOList, boolean force) { // 空列表判断,避免NPE if (CollectionUtils.isEmpty(someDTOList)) { return null; } List<String> weekNames = PeriodsUtils.getWeekNames(someDTOList.get(0).getWeekName()); String codeToReturn = someDTOList.get(0).getCode(); List<Integer> oldPIList = new ArrayList<>(); // 提取去重后的code集合,替代手动维护HashSet List<String> distinctCodes = someDTOList.stream() .map(SomeDTO::getCode) .distinct() .collect(Collectors.toList()); // 批量处理旧数据并构建待保存的uploadLog List<SomeEntity> uploadLogToSaveList = distinctCodes.stream().map(code -> { // 查询旧数据,用Optional避免多层null判断 SomeEntity oldPI = Optional.ofNullable(someRepository.findOneByCsuCodeEqualsAndWeekNumberEqualsAndApprovalStatusNotLikeOrderByUploadLogIdDesc( code, weekNames.get(0), APPROVED_STATUS)) .orElseGet(() -> { if (weekNames.size() == 2) { return someRepository.findOneByCsuCodeEqualsAndWeekNumberEqualsAndApprovalStatusNotLikeOrderByUploadLogIdDesc( code, weekNames.get(1), APPROVED_STATUS); } return null; }); if (oldPI != null) { oldPIList.add(oldPI.getUploadLogId()); } return new SomeEntity(code, weekNames.get(0)); }).collect(Collectors.toList()); // 批量删除旧数据,空列表直接跳过 if (!CollectionUtils.isEmpty(oldPIList)) { someRepository.deleteAllByIdInBatch(oldPIList); } // 保存新的uploadLog并构建code与uploadId的映射 List<SomeEntity> someEntityList = someRepository.saveAllAndFlush(uploadLogToSaveList); Map<String, Integer> codeUploadIdMap = someEntityList.stream() .collect(Collectors.toMap(SomeEntity::getCsuCode, SomeEntity::getUploadLogId)); // 处理每个DTO,避免嵌套stream提升可读性 someDTOList.forEach(product -> { String code = product.getCode(); Integer uploadId = codeUploadIdMap.get(code); if (uploadId == null) { // 提前抛出明确异常,便于排查问题 throw new IllegalArgumentException("未找到对应code的上传日志: " + code); } // 激活未激活产品 if (!product.isActive()) { pricingProductService.activateProduct(Long.valueOf(product.getProductCode())); } product.setId(0); product.setUploadLogId(uploadId); Integer weekId = modelPiWeekService.saveModelPiWeekDtoRestful(product).getId(); // 批量处理Delta数据,减少数据库交互次数 List<ModelPiWeekDeltaDTO> deltaList = getModelPiWeekDeltaDTOStream(product) .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(deltaList)) { // 建议新增批量保存方法,替代循环单条保存 modelPiWeekDeltaService.saveAllModelPiWeekDeltaDtoRestful(weekId, deltaList); } }); // 查询返回结果 return someRepository.findOneByCsuCodeEqualsAndWeekNumberEqualsAndApprovalStatusEqualsOrderByUploadLogIdDesc( codeToReturn, weekNames.get(0), "C"); }
优化说明
- 空值防护:添加
someDTOList空判断,避免调用get(0)时抛出NPE - 去重逻辑简化:用
stream().distinct()替代手动维护HashSet,代码更简洁易读 - 映射关系替代迭代器:用
Map<String, Integer>存储code和uploadId的对应关系,彻底解决迭代器耗尽问题 - null处理优化:用Optional封装Repository查询结果,减少多层if-null嵌套
- 性能优化:将Delta数据收集为List后批量保存(需service支持),减少数据库交互次数
- 可读性提升:将嵌套的stream遍历改为直接遍历
someDTOList,降低代码复杂度 - 异常明确化:添加uploadId为空的判断,提前抛出带有明确信息的异常,便于问题排查
内容的提问来源于stack exchange,提问作者Ranjana
相关产品推荐
相关产品推荐

