当前位置:首页 » 网络管理 » 增强for循环为什么可以删除
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

增强for循环为什么可以删除

发布时间: 2022-08-02 16:13:20

① HashMap和List遍历方法总结及如何遍历删除

(一)List的遍历方法及如何实现遍历删除
我们造一个list出来,接下来用不同方法遍历删除,如下代码:
List<String> list= new ArrayList<String>();famous.add("zs");famous.add("ls");famous.add("ww");famous.add("dz");

1、for循环遍历list:
for(int i=0;i<list.size();i++){if(list.get(i).equals("ls"))list.remove(i);}

这是一种很常见的遍历方式,但是使用这种遍历删除元素会出现问题,原因在于删除某个元素后,list的大小发生了变化,而你的索引
也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第一个元素后,继续根据索引访问第二个元素后,因为删除的原因,
后面的元素都往前移动了以为,所以实际访问的是第三个元素。因此,这种遍历方式可以用在读取元素,而不适合删除元素。
2、增强for循环:
for(String x:list){if(x.equals("ls"))list.remove(x);}

这也是一种很常见的遍历方式,但是使用这种遍历删除元素也会出现问题,运行时会报异常
其实增强for循环是java语法糖的一种体现,如果大家通过反编译得到字节码,那么上面这段代码的内部实现如下所示:

for(Iterator<String> it = list.iterator();it.hasNext();){String s = it.next();if(s.equals("madehua")){list.remove(s);}}

下面就解释为什么会报异常。分析Iterator的源代码,重点分析整个调用该过程中的
函数(hasNext和remove):

private class Itr implements Iterator<E> { 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 (); 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 (); } } */ final void checkForComodification() { // 检查修改和当前版本号是否一致,不一致则抛出异常 if (modCount != expectedModCount) throw new (); } } // 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.array(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.array(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<String> it = list.iterator();while(it.hasNext()){String x = it.next();if(x.equals("del")){it.remove();}}

这种方式是可以正常遍历和删除的。但是你可能看到上面代码感觉和增强for循环内部实现的代码差不多,其实差别就在于上面使用
一个使用list.remove(),一个使用it.remove()。

(二)HashMap的遍历删除及如何实现遍历删除
一样我们先造一个hashmap出来,如下:

private static HashMap<Integer, String> map = new HashMap<Integer, String>();; public static void main(String[] args) { for(int i = 0; i < 10; i++){ map.put(i, "value" + i); } }

1、第一种遍历删除:

for(Map.Entry<Integer, String> entry : map.entrySet()){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");}

这种遍历删除依旧会报异常,
2、第二种遍历删除:
Set<Integer> keySet = map.keySet(); 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"); } }

这种遍历删除依旧会报异常,
3、第三种遍历删除:
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();while(it.hasNext()){Map.Entry<Integer, String> entry = it.next();Integer key = entry.getKey();if(key % 2 == 0){ System.out.println("To delete key " + key); it.remove(); System.out.println("The key " + + key + " was deleted");}}

这种遍历是OK的
分析上述原因,如果大家理解了List的遍历删除,那么感觉HashMap的遍历删除是不是有类似之处啊。下面就分析一下原因:
如果查询源代码以上的三种的删除方式都是通过调用HashMap.removeEntryForKey方法来实现删除key的操作。
在removeEntryForKey方法内知识一场了key modCount就会执行一次自增操作,此时modCount就与expectedModCOunt不一致了
,上面三种remove实现中,只有第三种iterator的remove方法在调用完removeEntryForKey方法后同步了expectedModCount值与
modCount相同,所以iterator方式不会抛出异常。最后希望大家遇到问题到查询源代码,它会给你最好的解释!

② java里增强for循环【for(String a : arrayList)】里面可以修改数据吗

java里增强for循环【for(String a:arrayList)】里面可以修改数据,但是不能删除数据,如下例子:


修改集合:

importjava.util.ArrayList;
importjava.util.List;


publicclassTestA{

publicstaticvoidmain(String[]args){
//集合
List<String>arrayList=newArrayList<String>();
//存放元素
arrayList.add("hello");
arrayList.add("ninghao");
arrayList.add("bye");
//集合标量
intindex=0;
//遍历集合
for(Stringa:arrayList){
//输出集合对象
System.out.println(a);
//修改集合对象
arrayList.set(index,"hi");
//标量加一
index++;
}
//输出集合
System.out.println(arrayList);
}
}

结果:
hello
ninghao
bye
[hi,hi,hi]

删除集合元素:

importjava.util.ArrayList;
importjava.util.List;


publicclassTestA{

publicstaticvoidmain(String[]args){
//集合
List<String>arrayList=newArrayList<String>();
//存放元素
arrayList.add("hello");
arrayList.add("ninghao");
arrayList.add("bye");
//集合标量
intindex=0;
//遍历集合
for(Stringa:arrayList){
//输出集合对象
System.out.println(a);
//删除元素
arrayList.remove(index);

//标量加一
index++;
}
//输出集合
System.out.println(arrayList);
}
}
结果:
hello
Exceptioninthread"main"java.util.
atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
atjava.util.AbstractList$Itr.next(AbstractList.java:343)
atapp.TestA.main(TestA.java:19)

由以上例子可以看出,增强for循环,在循环里可以修改集合元素,但是不能删除集合元素。

③ 增强for循环怎么删除集合的元素

一个循环迭代,跟集合的增删改没什么关系。修改集合不是for去做的。
for只管循环迭代,你在循环里边修改集合,改变集合的长度,顺序对循环都有影响

④ 增强for循环的内部也就是调用iteratoer实现的吗请举出点证据。不要只回答是或者不是。

1.首先增强for循环和iterator遍历的效果是一样的,也就说增强for循环的内部也就是调用iteratoer实现的,

但是增强for循环有些缺点,例如不能在增强循环里动态的删除集合内容。不能获取下标等。
2.ArrayList由于使用数组实现,因此下标明确,最好使用普通循环。
3.而对于LinkedList 由于获取一个元素,要从头开始向后找,因此建议使用增强for循环,也就是iterator。

⑤ JAVA增强for循环为什么不能增删集合

foreach循环规定,只能查看集合元素.不能对齐进行增删改.如果你要增删改,必须事后立马跳出foreach循环.
这里说的foreach即使增强for循环!

⑥ 增强for循环和传统for循环有什么区别

增强for循环亦为高级for循环。

增强for循环内部是使用的Iterator来遍历的,只能遍历数组和实现了Iterable接口的集合。优点是写法简便,无需获得数组、集合长度,也无需根据索引来访问元素。缺点是不能在循环里动态的删除元素和获取元素下标。

任何的增强for循环都可以改写为普通for循环。遍历集合所有元素的话用增强for循环更加简洁,如果是复杂的循环,还是用for循环比较好,for循环功支持索引取元素,可以使用下标来控制位置。

高级for有一个局限性,必须有被遍历的目标。
建议在遍历数组的时候,还是希望使用传统for,因为传统for可以定义角标。
凡是支持迭代器的都支持高级for

.而对于 LinkedList 由于获取一个元素,要从头开始向后找,因此建议使用 增强for循环,也就是iterator。

下面用一个例子说明这点:

代码一

(List<Integer>lst)

  • {

  • for(Integerx:lst)

  • if(x%2==0)

  • lst.remove(x);

  • System.out.println(lst);

  • }

  • public static void removeEvensVer2(List<Integer> lst)

  • {

  • for (Integer x : lst)

  • if (x % 2 == 0)

  • lst.remove(x);


  • System.out.println(lst);

  • }


  • 代码二

  • (List<Integer>lst)

  • {

  • Iterator<Integer>itr=lst.iterator();

  • while(itr.hasNext())

  • if(itr.next()%2==0)

  • itr.remove();

  • System.out.println(lst);

  • }

  • public static void removeEvensVer3(List<Integer> lst)

  • {

  • Iterator<Integer> itr = lst.iterator();

  • while (itr.hasNext())

  • if (itr.next() % 2 == 0)

  • itr.remove();


  • System.out.println(lst);

  • }


  • 代码一在运行时抛出异常,代码二正常

  • 原因分析:因为增强的for循环内部就是调用iterator实现的,在遍历的时候就将list转化为了迭代器,当迭代器被创建之后,如果从结构上对列表修改除非通过迭代器自身的remove、add方法,其他任何时间任何方式的修改,迭代器都会抛出异常。