如何用Filter替代forEach中的判断,限制List元素最多出现两次
用Stream Filter替换forEach判断,限制List元素最多出现两次
需求说明
现有两个List<Long>集合keys和newKeys,以及返回新键列表的getNewKeys()方法,要求keys中每个元素最多出现两次。需要将原来在newKeys.stream().forEach()中通过判断元素是否已达两次来控制添加的逻辑,替换为Filter操作,过滤掉那些会导致keys中元素出现次数超过两次的newKeys元素。
解决方案
核心思路是先统计keys中各元素的现有出现次数,为每个元素分配最多可新增的配额(2 - 现有次数),在过滤newKeys时动态扣减配额,只保留配额充足的元素。
代码实现
import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; // 1. 统计keys中各元素的现有数量 Map<Long, Long> existingCount = keys.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); // 2. 初始化每个元素的可新增配额:最多2次,减去已有的数量,最小为0 Map<Long, AtomicInteger> remainingQuota = new HashMap<>(); existingCount.forEach((key, count) -> { int quota = Math.max(0, 2 - count.intValue()); remainingQuota.put(key, new AtomicInteger(quota)); }); // 3. 过滤newKeys,只保留不会导致元素超量的元素 List<Long> filteredNewKeys = newKeys.stream() .filter(key -> { // 若元素不在配额表中,默认配额为2(原keys中无此元素,最多可加2次) AtomicInteger quota = remainingQuota.computeIfAbsent(key, k -> new AtomicInteger(2)); // 配额>0时保留元素,同时扣减1次配额 return quota.getAndDecrement() > 0; }) .collect(Collectors.toList()); // 4. 将过滤后的元素添加到keys中 keys.addAll(filteredNewKeys);
示例验证
针对需求中的5种场景,上述代码的处理结果完全符合预期:
- 场景1:
Keys={}, NewKeys={}→ 过滤后无元素,keys保持为空 - 场景2:
Keys={1}, NewKeys={1}→ 元素1被保留,添加后keys变为{1,1} - 场景3:
Keys={1}, NewKeys={1,1}→ 仅保留1个1,添加后keys变为{1,1}(移除了1个1) - 场景4:
Keys={1,1}, NewKeys={1,1}→ 所有1被过滤,keys保持{1,1}(移除所有1) - 场景5:
Keys={}, NewKeys={1,1,1}→ 保留2个1,添加后keys变为{1,1}(移除了1个1)
补充说明
- 代码使用
AtomicInteger存储配额,支持并行流处理(线程安全);若仅使用顺序流,也可替换为普通Integer配合同步代码块,但AtomicInteger实现更简洁高效。 - 若
newKeys来自getNewKeys()方法,直接将newKeys替换为getNewKeys()即可:getNewKeys().stream()...
内容的提问来源于stack exchange,提问作者kylie.zoltan
相关产品推荐
相关产品推荐

