欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java HashMap 如何正确遍历并删除元素的方法小结

程序员文章站 2023-11-05 17:27:22
(一)hashmap的遍历 hashmap的遍历主要有两种方式: 第一种采用的是foreach模式,适用于不需要修改hashmap内元素的遍历,只需要获取元素的键/值的...

(一)hashmap的遍历

hashmap的遍历主要有两种方式:

第一种采用的是foreach模式,适用于不需要修改hashmap内元素的遍历,只需要获取元素的键/值的情况。

hashmap<k, v> myhashmap;
for (map.entry<k, v> item : myhashmap.entryset()){
  k key = item.getkey();
  v val = item.getvalue();
  //todo with key and val
  //warning: do not change key and val if you want to remove items later
}

第二种采用迭代器遍历,不仅适用于hashmap,对其它类型的容器同样适用。

采用这种方法的遍历,可以用下文提及的方式安全地对hashmap内的元素进行修改,并不会对后续的删除操作造成影响。

for (iterator<map.entry<k, v>> it = myhashmap.entryset().iterator; it.hasnext();){
  map.entry<k, v> item = it.next();
  k key = item.getkey();
  v val = item.getvalue();
  //todo with key and val
  //you may remove this item using "it.remove();"
}

(二)hashmap之删除元素

如果采用第一种的遍历方法删除hashmap中的元素,java很有可能会在运行时抛出异常。

hashmap<string, integer> myhashmap = new hashmap<>();
myhashmap.put("1", 1);
myhashmap.put("2", 2);
for (map.entry<string, integer> item : myhashmap.entryset()){
  myhashmap.remove(item.getkey());
}
for (map.entry<string, integer> item : myhashmap.entryset()){
  system.out.println(item.getkey());

运行上面的代码,java抛出了 java.util.concurrentmodificationexception 的异常。并附有如下信息。

at java.util.hashmap$hashiterator.nextnode(unknown source)
at java.util.hashmap$entryiterator.next(unknown source)
at java.util.hashmap$entryiterator.next(unknown source)

可以推测,由于我们在遍历hashmap的元素过程中删除了当前所在元素,下一个待访问的元素的指针也由此丢失了。

所以,我们改用第二种遍历方式。

代码如下:

for (iterator<map.entry<string, integer>> it = myhashmap.entryset().iterator(); it.hasnext();){
  map.entry<string, integer> item = it.next();
  //... todo with item
  it.remove();
}
for (map.entry<string, integer> item : myhashmap.entryset()){
  system.out.println(item.getkey());
}

运行结果没有显示,表明hashmap中的元素被正确删除了。

(三)在hashmap的遍历中删除元素的特殊情况

上述方法可能足以应付多数的情况,但是如果你的hashmap中的键值同样是一个hashmap,假设你需要处理的是 hashmap<hashmap<string, integer>, double> myhashmap 时,很不碰巧,你可能需要修改myhashmap中的一个项的键值hashmap中的某些元素,之后再将其删除。

  这时,单单依靠迭代器的 remove() 方法是不足以将该元素删除的。

  例子如下:

hashmap<hashmap<string, integer>, integer> myhashmap = new hashmap<>();
hashmap<string, integer> temp = new hashmap<>();
temp.put("1", 1);
temp.put("2", 2);
myhashmap.put(temp, 3);
for (iterator<map.entry<hashmap<string, integer>, integer>> 
  it = myhashmap.entryset().iterator(); it.hasnext();){
  map.entry<hashmap<string, integer>, integer> item = it.next();
  item.getkey().remove("1");
  system.out.println(myhashmap.size());
  it.remove();
  system.out.println(myhashmap.size());
}

结果如下:

1
1

虽然 it.remove(); 被执行,但是并没有真正删除元素。

原因在于期望删除的元素的键值(即 hashmap<string, integer> temp )被修改过了。

解决方案:

既然在这种情况下,hashmap中被修改过的元素不能被删除,那么不妨直接把待修改的元素直接删除,再将原本所需要的“修改过”的元素加入hashmap。

想法很好,代码如下:

for (iterator<map.entry<hashmap<string, integer>, integer>> 
  it = myhashmap.entryset().iterator(); it.hasnext();){
  map.entry<hashmap<string, integer>, integer> item = it.next();
  //item.getkey().remove("1");
  hashmap<string, integer> to_put = new hashmap<>(item.getkey());
  to_put.remove("1");
  myhashmap.put(to_put, item.getvalue());
  system.out.println(myhashmap.size());
  it.remove();
  system.out.println(myhashmap.size());
}

但是依然是re:

exception in thread "main" java.util.concurrentmodificationexception
    at java.util.hashmap$hashiterator.remove(unknown source)

原因在于,迭代器遍历时,每一次调用 next() 函数,至多只能对容器修改一次。上面的代码则进行了两次修改:一次添加,一次删除。

既然 java.util.concurrentmodificationexception 异常被抛出了,那么去想办法拿掉这个异常即可。

最后的最后,我决定弃hashmap转投concurrenthashmap。将myhashmap定义为concurrenthashmap之后,其它代码不动。

运行结果如下:

2
1

最终,通过concurrenthashmap和一些小技巧的使用,变形实现了对被修改过键值的元素的删除。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。