Java Stream操作Map时过滤排序后返回空列表是什么原因?
问题根因
Java Stream 采用惰性求值机制,只有调用终端操作才会触发整条流逻辑的执行:
- 你编写的第二个流链只定义了
filter、sorted、limit、peek4个中间操作,没有添加任何终端操作(如collect、forEach、count等),因此整个流逻辑完全没有运行,peek中往结果列表添加元素的代码从未执行,所以返回空列表。 - 额外优化建议:你的代码对过滤后的流做了两次遍历(一次统计总数、一次处理数据),存在不必要的性能开销;同时
peek官方定义为调试用途,不推荐用来执行业务副作用操作。
修正后的代码示例
最优写法(一次遍历完成所有逻辑)
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public List<String> getValuableSubStr(){ return map.entrySet().stream() // 过滤key长度为3的条目 .filter(e -> e.getKey().length() == 3) // 按key降序排序 .sorted(Map.Entry.<String, Integer>comparingByKey().reversed()) // 提取key .map(Map.Entry::getKey) // 收集后截取前5% .collect(Collectors.collectingAndThen(Collectors.toList(), allValidKeys -> { int limit = (int) (allValidKeys.size() * 0.05); // 可根据需求添加边界判断,例如不足1个时至少取1条:limit = Math.max(limit, 1); return limit <= 0 ? new ArrayList<>() : allValidKeys.subList(0, limit); })); }
原有逻辑最小改动版本
如果不想调整原有逻辑结构,只需要把peek替换为终端操作forEach即可触发流执行:
public List<String> getValuableSubStr(){ List<String> result = new ArrayList<>(); long size = map.entrySet().stream().filter(e -> e.getKey().length() ==3).count(); map.entrySet().stream() .filter(e -> e.getKey().length() ==3) .sorted(Map.Entry.<String,Integer>comparingByKey().reversed()) .limit((size*5)/100) // 把peek换成终端操作forEach触发流执行 .forEach(e -> result.add(e.getKey())); return result; }
内容的提问来源于stack exchange,提问作者Alpharius
相关产品推荐
相关产品推荐

