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

基于Map定义PriorityQueue时触发NullPointerException问题求助

PriorityQueue排序时出现NullPointerException的原因分析

你的代码片段

Map<Integer, Integer> map = new HashMap<>();
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> map.get(b[1]) == map.get(a[1]) ? b[2] - a[2] : map.get(b[1]) - map.get(a[1]));
List<List<Integer>> l = new ArrayList<>();

public TaskManager(List<List<Integer>> tasks) {
    for(List<Integer> t: tasks) {
        map.put(t.get(1), t.get(2));
        pq.add(new int[]{t.get(0), t.get(1), t.get(2)});
    }
}

触发的错误

java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null

原因分析

  1. PriorityQueue比较器的延迟执行特性
    PriorityQueue不会在调用add()时完成全量排序,仅维护堆的基础有序状态。只有当执行poll()、peek()、队列扩容等操作时,才会触发比较器的调用。这意味着如果在add()元素后,map中的对应键被移除、或值被设为null,后续触发比较器时就会返回null,抛出NPE。

  2. 不必要的外部依赖(核心问题)
    你的队列元素int[]中已经携带了排序所需的t.get(2)(数组第三个元素),但你却选择通过外部map获取该值。这种冗余的依赖完全没必要,还把比较器逻辑和map强绑定,一旦map状态被意外修改(比如其他代码删除了键),就会触发异常。

  3. 潜在的并发或键值问题
    如果是多线程环境,多个线程同时修改map和操作pq,可能出现调用map.get()时键已被移除的情况;另外如果tasks中存在t.get(1)为null的情况,后续若删除map中的null键,也会导致map.get(null)返回null。

修复方案

最优方案:摆脱对外部map的依赖

直接使用队列元素自身携带的值进行排序,彻底消除NPE风险:

PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {
    // 先按原map对应的值降序排序(即数组第三个元素)
    int valueCompare = Integer.compare(b[2], a[2]);
    if (valueCompare != 0) {
        return valueCompare;
    }
    // 值相等时,按原逻辑用数组第三个元素降序(可根据实际需求调整)
    return b[2] - a[2];
});

若需保留map的其他用途

如果map还有其他查询需求,需确保:

  • 整个PriorityQueue生命周期内,map不会移除已存入的键,也不会将对应值设为null;
  • 多线程环境下,对map和pq的操作加锁,或使用线程安全集合(如ConcurrentHashMap、PriorityBlockingQueue)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:41:01