有一个朋友经常说:最基础的东西最磨人。
这两天遇到一个,哭笑不得的HashMap删除空指针,抓紧时间记录。
一、原始需求
原始需求只是从resourcekeyMap一个普通的HashMap中获取数据存入一个普通的名叫resourceList的ArrayList中
代码如下:
Collection collection = resourceKeyMap.values();
collection.forEach((resource)->resourceList.add(resource));
二、增加需求
现在需要将resource中structNodeId为空的数据剔除,就出现空指针异常。
如果没有debug,也没有这个经验的人,一眼看过去发现不了这个空指针,不信你试试。
展示我的原始代码:
Collection collections = resourceKeyMap.values();
for (Object resource1:collections) {
Resource resource = (Resource)resource1;
if(resource.getStructNodeId()!=null){
resourceList.add(resource);
}else{
resourceKeyMap.remove(resource.getResourceId());
}
}
很清晰的代码,是吧。
三、发现异常,解释异常
这行代码
resourceKeyMap.remove(resource.getResourceId());
在删除的时候,会出现异常
分析原因:
在遍历HashMap的元素过程中,Map中有key对应的指针进行下一个数据的指向,如果此时删除了当前所在元素,下一个待访问的元素的指针也由此丢失了,
正常情况下,此时应该放上源码,再做解释,但是太啰嗦了,今天时间紧促,着急吃饭,直接上解释:
HahMap基本原理:
先声明一个下标范围比较大的数组来存储元素。另外设计一个哈希函数(也叫做散列函数)来获得每一个元素的Key(关键字)的函数值(即数组下标,hash值)相对应,数组存储的元素是一个Entry类,这个类有三个数据域,key、value(键值对),next(指向下一个Entry)。
请注意这个next
例如, 第一个键值对A进来。通过计算其key的hash得到的index=0。记做:Entry[0] = A。
第二个键值对B,通过计算其index也等于0, HashMap会将B.next =A,Entry[0] =B, 第三个键值对
C,index也等于0,那么C.next = B,Entry[0] =
C;这样我们发现index=0的地方事实上存取了A,B,C三个键值对,它们通过next这个属性链接在一起。我们可以将这个地方称为桶。
如果删除了这个节点,那就直接删除了这个Entry,包括key、value,next,所以再进行遍历的时候,发现存在值,但是死活找不到,无奈之下,只能报异常,引起注意。
四、解决办法
//iterator遍历
for(Iterator<Resource> iterator = resourceKeyMap.values().iterator();iterator.hasNext();) {
Resource resource = iterator.next();
if (resource.getStructNodeId() != null) {
resourceList.add(resource);
} else {
iterator.remove();
}
}
使用iterator迭代器,原理就是数据的再一次复制,保证了这个查询过程的连续性。
五、提供完整代码,方便测试
public static void main(String[] args) {
Map<String,String> resourceMap = new HashMap<>();
resourceMap.put("111","111");
resourceMap.put("222","222");
resourceMap.put("333","333");
for(Iterator<String> iterator = resourceMap.values().iterator();iterator.hasNext();){
String resource = iterator.next();
if(!resource.equals("222")){
System.out.println(resource);
}else{
iterator.remove();
}
}
resourceMap.values().forEach(srting-> System.out.println(srting));
}
注意:以后触及到删除HahMap的操作,一定要想起迭代器。
THE END
GOOD LUNCK