Flutter开发App的未来及其在各行业的应用潜力分析
447
2023-08-06
HashMap和List遍历方法及如何遍历删除元素总结
相信大家对集合遍历再熟悉不过了,这里总结一下HashMap和List的遍历方法,以及它们该如何实现遍历删除。
这里对于每种遍历删除出现的问题的原因都给出了详解!
(一)List的遍历方法及如何实现遍历删除
我们造一个list出来,接下来用不同方法遍历删除,如下代码:
List
famous.add("zs");
famous.add("ls");
famous.add("ww");
famous.add("dz");
1、for循环遍历list:
for(int i=0;i if(list.get(i).equals("ls")) list.remove(i); } 这是一种很常见的遍历方式,但是使用这种遍历删除元素会出现问题,原因在于删除某个元素后,list的大小发生了变化,而你的索引也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第一个元素后,继续根据索引访问第二个元素后,因为删除的原因,后面的元素都往前移动了以为,所以实际访问的是第三个元素。因此,这种遍历方式可以用在读取元素,而不适合删除元素。 2、增强for循环: for(String x:list){ if(x.equals("ls")) list.remove(x); } 这也是一种很常见的遍历方式,但是使用这种遍历删除元素也会出现问题,运行时会报ConcurrentModificationException异常 其实增强for循环是java语法糖的一种体现,如果大家通过反编译得到字节码,那么上面这段代码的内部实现如下所示: for(http://Iterator String s = it.next(); if(s.equals("madehua")){ list.remove(s); } } 下面就解释为什么会报ConcurrentModificationException异常。分析Iterator的源代码,重点分析整个调用该过程中的 函数(hasNext和remove): private class Itr implements Iterator int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; // size为集合中元素的个数 } public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } /* 此方法并没被调用,只是调用List.remove方法 public void remove() { checkForComodification(); try { ArrayList.this.remove(lastRet); // size字段减1 cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } */ final void checkForComodification() { // 检查修改和当前版本号是否一致,不一致则抛出异常 if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } // List.remove @Override public boolean remove(Object object) { Object[] a = array; int s = size; if (object != null) { for (int i = 0; i < s; i++) { if (object.equals(a[i])) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; // 核心代码:修改了版本号。这样当checkForComodification的时候,modCount值就和expectedModCount不同 return true; } } } else { for (int i = 0; i < s; i++) { if (a[i] == null) { System.arraycopy(a, i + 1, a, i, --s - i); a[s] = null; // Prevent memory leak size = s; modCount++; return true; } } } return false; } 接下来梳理一下流程,这时候你就会发现这个异常是在next方法的checkForComodification中抛出的。抛出的原因是 modCount !=expectedModCount。这里的modCount是指这个list对象从呢我出来到现在被修改的次数,当调用list 的add或者remove方法的时候,这个modCount都会自动增减;iterator创建的时候modCount被复制给了 expectedModcount,但是调用list的add和remove方法的时候不会同时自动增减expectedModcount,这样就导致 两个count不相等,从而抛出异常。大家如果理解了上面的执行流程,以后碰到类似这种问题,比如如果删除的是倒数 第二个元素却不会碰到异常。就会知道为什么了。 3、iterator遍历删除 Iterator while(it.hasNext()){ String x = it.next(); if(x.equals("del")){ it.remove(); } } 这种方式是可以正常遍历和删除的。但是你可能看到上面代码感觉和增强for循环内部实现的代码差不多,其实差别就在于上面使用一个使用list.remove(),一个使用it.remove()。 (二)HashMap的遍历删除及如何实现遍历删除 一样我们先造一个hashmap出来,如下 private static HashMap public static void main(String[] args) { for(int i = 0; i < 10; i++){ map.put(i, "value" + i); } } 1、第一种遍历删除: for(Map.Entry Integer key = entry.getKey(); if(key % 2 == 0){ System.out.println("To delete key " + key); map.remove(key); System.out.println("The key " + + key + " was deleted"); } 这种遍历删除依旧会报ConcurrentModificationException异常, 2、第二种遍历删除: Set for(Integer key : keySet){ if(key % 2 == 0){ System.out.println("To delete key " + key); keySet.remove(key); System.out.println("The key " + + key + " was deleted"); } } 这种遍历删除依旧会报ConcurrentModificationException异常, 3、第三种遍历删除: Iterator while(it.hasNext()){ Map.Entry Integer key = entry.getKey(); if(key % 2 == 0){ System.out.println("To delete key " + key); it.remove(); System.out.printlCZDFwrjAn("The key " + + key + " was deleted"); } } 这种遍历是OK的
if(list.get(i).equals("ls"))
list.remove(i);
}
这是一种很常见的遍历方式,但是使用这种遍历删除元素会出现问题,原因在于删除某个元素后,list的大小发生了变化,而你的索引也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第一个元素后,继续根据索引访问第二个元素后,因为删除的原因,后面的元素都往前移动了以为,所以实际访问的是第三个元素。因此,这种遍历方式可以用在读取元素,而不适合删除元素。
2、增强for循环:
for(String x:list){
if(x.equals("ls"))
list.remove(x);
}
这也是一种很常见的遍历方式,但是使用这种遍历删除元素也会出现问题,运行时会报ConcurrentModificationException异常
其实增强for循环是java语法糖的一种体现,如果大家通过反编译得到字节码,那么上面这段代码的内部实现如下所示:
for(http://Iterator
String s = it.next();
if(s.equals("madehua")){
list.remove(s);
}
}
下面就解释为什么会报ConcurrentModificationException异常。分析Iterator的源代码,重点分析整个调用该过程中的
函数(hasNext和remove):
private class Itr implements Iterator
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size; // size为集合中元素的个数
}
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
/* 此方法并没被调用,只是调用List.remove方法
public void remove() {
checkForComodification();
try {
ArrayList.this.remove(lastRet); // size字段减1
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
*/
final void checkForComodification() { // 检查修改和当前版本号是否一致,不一致则抛出异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
// List.remove
@Override public boolean remove(Object object) {
Object[] a = array;
int s = size;
if (object != null) {
for (int i = 0; i < s; i++) {
if (object.equals(a[i])) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++; // 核心代码:修改了版本号。这样当checkForComodification的时候,modCount值就和expectedModCount不同
return true;
}
}
} else {
for (int i = 0; i < s; i++) {
if (a[i] == null) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return true;
}
}
}
return false;
}
接下来梳理一下流程,这时候你就会发现这个异常是在next方法的checkForComodification中抛出的。抛出的原因是
modCount !=expectedModCount。这里的modCount是指这个list对象从呢我出来到现在被修改的次数,当调用list
的add或者remove方法的时候,这个modCount都会自动增减;iterator创建的时候modCount被复制给了
expectedModcount,但是调用list的add和remove方法的时候不会同时自动增减expectedModcount,这样就导致
两个count不相等,从而抛出异常。大家如果理解了上面的执行流程,以后碰到类似这种问题,比如如果删除的是倒数
第二个元素却不会碰到异常。就会知道为什么了。
3、iterator遍历删除
Iterator
while(it.hasNext()){
String x = it.next();
if(x.equals("del")){
it.remove();
}
}
这种方式是可以正常遍历和删除的。但是你可能看到上面代码感觉和增强for循环内部实现的代码差不多,其实差别就在于上面使用一个使用list.remove(),一个使用it.remove()。
(二)HashMap的遍历删除及如何实现遍历删除
一样我们先造一个hashmap出来,如下
private static HashMap
public static void main(String[] args) {
for(int i = 0; i < 10; i++){
map.put(i, "value" + i);
}
}
1、第一种遍历删除:
for(Map.Entry
Integer key = entry.getKey();
if(key % 2 == 0){
System.out.println("To delete key " + key);
map.remove(key);
System.out.println("The key " + + key + " was deleted");
}
这种遍历删除依旧会报ConcurrentModificationException异常,
2、第二种遍历删除:
Set
for(Integer key : keySet){
if(key % 2 == 0){
System.out.println("To delete key " + key);
keySet.remove(key);
System.out.println("The key " + + key + " was deleted");
}
}
这种遍历删除依旧会报ConcurrentModificationException异常,
3、第三种遍历删除:
Iterator
while(it.hasNext()){
Map.Entry
Integer key = entry.getKey();
if(key % 2 == 0){
System.out.println("To delete key " + key);
it.remove();
System.out.printlCZDFwrjAn("The key " + + key + " was deleted");
}
}
这种遍历是OK的
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~