如何用Streams将Map<String,UserStats>数组转为Map<Long,Long>并修复异常
问题解决:将
Map<String, UserStats>[]转为Map<Long, Long>的正确实现 问题根源
- 空Map触发NPE:你创建的
m1数组长度为10,仅初始化了索引0和1的位置,其余位置都是null,直接调用m.forEach会抛出空指针异常。 - 未收集处理结果:原方法返回的是初始空的
visitsNum,完全没有把Stream处理后的Map结果合并进去。 - 空字符串Key未过滤:空字符串
""解析Long会抛出异常,需要提前过滤这类无效Key。 - 冗余逻辑与不优雅的Optional处理:手动初始化
count1=0L可以用Optional的默认值替代,UserStats为null时直接跳过即可,无需额外分支。
修正后的完整代码
import java.util.*; import java.util.stream.Collectors; public class Sample { Map<Long, Long> count(Map<String, UserStats>[] visits) { return Arrays.stream(visits) // 过滤数组中未初始化的null Map .filter(Objects::nonNull) // 将每个Map的Entry扁平化为单一流 .flatMap(map -> map.entrySet().stream()) // 过滤null或空白字符串的Key .filter(entry -> entry.getKey() != null && !entry.getKey().isBlank()) // 转换每个Entry为目标键值对,无效情况返回null .map(entry -> { String keyStr = entry.getKey(); UserStats userStats = entry.getValue(); // 解析字符串为Long,失败则跳过 Long microserviceId; try { microserviceId = Long.parseLong(keyStr); } catch (NumberFormatException e) { System.out.println("微服务编号不是Long类型: " + keyStr); return null; } // 过滤null的UserStats if (userStats == null) { System.out.println("用户未访问微服务: " + microserviceId); return null; } // 提取VisitCounter,空则默认0L Long visitCount = userStats.VisitCounter().orElse(0L); System.out.println("用户访问微服务 " + microserviceId + " 的次数: " + visitCount); return new AbstractMap.SimpleEntry<>(microserviceId, visitCount); }) // 过滤掉处理过程中产生的null条目 .filter(Objects::nonNull) // 收集为最终Map,重复Key取最后一个值(可按需调整合并逻辑) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (existing, replacement) -> replacement )); } record UserStats(Optional<Long> VisitCounter) {} public static void main(String[] args) { Sample a = new Sample(); UserStats u = new UserStats(Optional.of(10L)); UserStats u1 = new UserStats(Optional.of(20L)); Map<String, UserStats>[] m1 = new HashMap[10]; Map<String, UserStats> m2 = new HashMap<>(); Map<String, UserStats> m3 = new HashMap<>(); m2.put("20", u); m2.put("30", u1); m3.put("", u); m3.put("50", null); m1[0] = m2; m1[1] = m3; Map<Long, Long> visitsNum = a.count(m1); System.out.println("最终结果Map: " + visitsNum); } }
关键修改说明
- 过滤null Map:用
filter(Objects::nonNull)跳过数组中未初始化的null元素,从根源避免NPE。 - 扁平化处理:通过
flatMap将多个Map的Entry流合并为一个全局流,简化后续统一处理。 - 提前过滤无效Key:先筛掉
null或空白字符串的Key,避免后续解析Long时的异常。 - 简化Optional处理:用
orElse(0L)替代手动判断isPresent(),代码更简洁。 - 正确收集结果:通过
Collectors.toMap直接将有效Entry收集为目标Map,同时处理重复Key的场景(这里采用覆盖策略,可根据业务需求调整合并逻辑)。 - 跳过无效条目:转换过程中遇到解析失败、UserStats为null的情况时返回
null,再通过filter(Objects::nonNull)过滤这些无效条目。
运行结果
用户访问微服务 20 的次数: 10 用户访问微服务 30 的次数: 20 微服务编号不是Long类型: 用户未访问微服务: 50 最终结果Map: {20=10, 30=20}
内容的提问来源于stack exchange,提问作者Jaya
相关产品推荐
相关产品推荐

