Java Stream使用flatMap后如何收集父对象至Set集合
解决方案
你遇到的问题核心是flatMap的作用是将父对象流转换为子对象的流,所以后续操作的元素都是ContractDetailsEntity,自然无法收集到UnifiedOfferEntity类型的集合。
要实现需求,不需要使用flatMap,而是在父对象的过滤阶段,判断其嵌套的contractDetails集合中是否存在符合条件的子元素,这样整个流始终保持UnifiedOfferEntity类型,最终就能收集到目标集合。
修改后的代码
List<UnifiedOfferEntity> offersFromDB = // 初始化逻辑 Set<UnifiedOfferEntity> result = offersFromDB.stream() // 第一步:过滤父对象的技能、资历条件 .filter(offer -> CollectionUtils.containsAny(preferences.getOwnedSkills(), offer.getSkills()) && CollectionUtils.containsAny(preferences.getOwnedSeniority(), offer.getSeniority())) // 第二步:判断该父对象是否存在符合条件的ContractDetailsEntity .filter(offer -> offer.getContractDetails().stream() .anyMatch(cd -> cd.getSalaryFrom() >= preferences.getSalaryMin() && cd.getSalaryTo() <= preferences.getSalaryMax() && tocPreferences.contains(cd.getTypeOfContract()))) // 收集父对象到Set .collect(Collectors.toSet());
逻辑说明
anyMatch是短路操作:只要找到第一个符合条件的ContractDetailsEntity就会停止遍历,性能上比遍历整个集合更高效。- 整个流的元素始终是
UnifiedOfferEntity,所以最终collect得到的就是Set<UnifiedOfferEntity>,完全符合你的需求。
额外扩展(如果需要保留过滤后的子集合)
如果你后续需要同时保留父对象和其符合条件的子集合,可以在filter之后加上map操作,对父对象的contractDetails进行过滤并重新赋值:
Set<UnifiedOfferEntity> resultWithFilteredContracts = offersFromDB.stream() .filter(offer -> CollectionUtils.containsAny(preferences.getOwnedSkills(), offer.getSkills()) && CollectionUtils.containsAny(preferences.getOwnedSeniority(), offer.getSeniority())) .filter(offer -> offer.getContractDetails().stream() .anyMatch(cd -> cd.getSalaryFrom() >= preferences.getSalaryMin() && cd.getSalaryTo() <= preferences.getSalaryMax() && tocPreferences.contains(cd.getTypeOfContract()))) .map(offer -> { // 过滤出符合条件的ContractDetailsEntity Set<ContractDetailsEntity> filteredContracts = offer.getContractDetails().stream() .filter(cd -> cd.getSalaryFrom() >= preferences.getSalaryMin() && cd.getSalaryTo() <= preferences.getSalaryMax() && tocPreferences.contains(cd.getTypeOfContract())) .collect(Collectors.toSet()); // 注意:如果UnifiedOfferEntity是不可变类,需要创建新实例;可变类则直接修改 UnifiedOfferEntity filteredOffer = new UnifiedOfferEntity(); filteredOffer.setContractDetails(filteredContracts); // 复制其他字段... return filteredOffer; }) .collect(Collectors.toSet());
内容的提问来源于stack exchange,提问作者Lulex97
相关产品推荐
相关产品推荐

