You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Streams将Map<String,UserStats>数组转为Map<Long,Long>并修复异常

问题解决:将Map<String, UserStats>[]转为Map<Long, Long>的正确实现

问题根源

  1. 空Map触发NPE:你创建的m1数组长度为10,仅初始化了索引0和1的位置,其余位置都是null,直接调用m.forEach会抛出空指针异常。
  2. 未收集处理结果:原方法返回的是初始空的visitsNum,完全没有把Stream处理后的Map结果合并进去。
  3. 空字符串Key未过滤:空字符串""解析Long会抛出异常,需要提前过滤这类无效Key。
  4. 冗余逻辑与不优雅的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);
    }
}

关键修改说明

  1. 过滤null Map:用filter(Objects::nonNull)跳过数组中未初始化的null元素,从根源避免NPE。
  2. 扁平化处理:通过flatMap将多个Map的Entry流合并为一个全局流,简化后续统一处理。
  3. 提前过滤无效Key:先筛掉null或空白字符串的Key,避免后续解析Long时的异常。
  4. 简化Optional处理:用orElse(0L)替代手动判断isPresent(),代码更简洁。
  5. 正确收集结果:通过Collectors.toMap直接将有效Entry收集为目标Map,同时处理重复Key的场景(这里采用覆盖策略,可根据业务需求调整合并逻辑)。
  6. 跳过无效条目:转换过程中遇到解析失败、UserStats为null的情况时返回null,再通过filter(Objects::nonNull)过滤这些无效条目。

运行结果

用户访问微服务 20 的次数: 10
用户访问微服务 30 的次数: 20
微服务编号不是Long类型: 
用户未访问微服务: 50
最终结果Map: {20=10, 30=20}

内容的提问来源于stack exchange,提问作者Jaya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:24:50