为了账号安全,请及时绑定邮箱和手机立即绑定

ConcurrentHashMap 的值抛出 NullPointerException

ConcurrentHashMap 的值抛出 NullPointerException

神不在的星期二 2022-12-07 15:08:47
我正在维护使用ConcurrentHashMap.其他方法中有add和remove的操作。在下面的代码中,在从地图中收集了一些值后的某个时刻,它NullPointerException在执行时抛出synchronize(value)。public class MyClass{    private final Map<MyObj, Map<String, List<String>>> conMap = new ConcurrentHashMap<>();    //...    public void doSomthing((MyObj id){        List<Map<String, List<String>>> mapsList = new LinkedList<>();        for(MyObj objId: conMap.keySet()){                          if(objId.key1.equals(id.key1)){                mapsList.add(conMap.get(objId));            }        }        for(Map<String, List<String>> map: mapsList){            synchronized(map){                   // <-- NullPointerException here                //...            }    }    //...}我有一种感觉,也许在第一个循环的迭代过程中,记录被删除了。当行:mapsList.add(conMap.get(objId));正在执行,objId不再存在并mapsList添加 null,结果,在第二个循环期间NullPoinerException被抛出。还有其他原因可以得到这个例外吗?
查看完整描述

1 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

您已经爱上了 Check-Then-Act 反模式。它意味着检查条件(如密钥的存在),然后对其采取行动(如调用get),忽略条件可能在其间发生变化的可能性。


因此,您在迭代时遇到了一个特定的键conMap.keySet(),但在您调用conMap.get(objId)时,该键可能不再位于映射中,返回时会报告这一点null。


强烈建议使用具有合适hashCode/equals实现的键类型,这样您就无需遍历整个地图来查找匹配项,而是可以使用单个get(id).


但是,当您必须遍历映射并需要值时,请遍历条目集而不是键集。


public void doSomething(MyObj id){

    // see https://stackoverflow.com/q/322715/2711488

    List<Map<String, List<String>>> mapsList = new ArrayList<>();


    for(Map.Entry<MyObj, Map<String, List<String>>> e: conMap.entrySet()){              

        if(e.getKey().key1.equals(id.key1)){

            mapsList.add(e.getValue());

        }

    }


    for(Map<String, List<String>> map: mapsList){

        synchronized(map) {

            //...

        }

    }

}


查看完整回答
反对 回复 2022-12-07
  • 1 回答
  • 0 关注
  • 239 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号