Java增强for循环的增删操作代码
作者:loet6010
最近在看Java开发手册时,看到这样一条规定:
下面就来一探究竟,看看为什么会有这样的规定。
Foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素。foreach语法格式如下:
for( 元素类型T 元素变量t : 遍历对象obj){ 引用了t 的java 语句; }
以下实例演示了普通for循环和foreach循环使用:
private static void test() { List<String> names = new ArrayList<String>() {{ add("Hello"); add("World"); add("Good"); }}; System.out.println("foreach循环"); for (String name : names) { System.out.println(name); } System.out.println("普通for循环"); for (int i = 0; i < names.size(); i++) { System.out.println(names.get(i)); } }
输出结果如下:
foreach循环
Hello
World
Good
普通for循环
Hello
World
Good
可以看到,使用foreach语法遍历集合或者数组的时候,可以起到和普通for循环同样的效果,并且代码更加简洁。所以,foreach循环也通常也被称为增强for循环。
其实,增强for循环是Java给我们提供的一个语法糖,如果将以上代码编译后的class 文件进行反编译的话,可以得到以下代码:
private static void test() { List<String> names = new ArrayList<String>() { { this.add("Hello"); this.add("World"); this.add("Good"); } }; System.out.println("foreach循环"); Iterator var1 = names.iterator(); while(var1.hasNext()) { String name = (String)var1.next(); System.out.println(name); } System.out.println("普通for循环"); for(int i = 0; i < names.size(); ++i) { System.out.println((String)names.get(i)); } }
可以发现,原来增强for循环是依赖了while循环和Iterator实现的。规范中指出不让我们在foreach循环中对集合元素做add/remove操作,那么,我们尝试着做一下看看会发生什么问题。
private static void test() { List<String> names = new ArrayList<String>() {{ add("Hello"); add("World"); add("Good"); }}; System.out.println("增强for循环"); for (String name : names) { System.out.println(name); if ("Hello".equals(name)) { names.remove(name); } } }
增强for循环 Hello Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911) at java.util.ArrayList$Itr.next(ArrayList.java:861)
可以看到抛出了异常,追踪异常中的checkForComodification如下:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
这是ArrayList中的检测代码,那么这个modCount和expectedModCount又是什么东西呢?
通过翻源码,我们可以发现:
●● modCount是ArrayList中的一个成员变量。它表示该集合实际被修改的次数。
●● expectedModCount是ArrayList中的一个内部类——Itr中的成员变量。expectedModCount 表示这个迭代器期望该集合被修改的次数。其值是在ArrayList.iterator方法被调用的时候初始化的。只有通过迭代器对集合进行操作,该值才会改变。
●● Itr是一个Iterator的实现,使用ArrayList.iterator方法可以获取到的迭代器就是Itr类的实例。
他们之间的关系如下:
class ArrayList{ private int modCount; public void add(); public void remove(); private class Itr implements Iterator<E> { int expectedModCount = modCount; } public Iterator<E> iterator() { return new Itr(); } }
remove方法核心逻辑如下:
/* * Private remove method that skips bounds checking and does not * return the value removed. */ private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }
可以看到,它只修改了modCount,并没有对expectedModCount做任何操作。
之所以会抛出ConcurrentModificationException异常,是因为我们的代码中使用了增强for循环,而在增强for循环中,集合遍历是通过iterator进行的,但是元素的add/remove却是直接使用的集合类自己的方法。这就导致iterator在遍历的时候,会发现有一个元素在自己不知不觉的情况下就被删除/ 添加
,就会抛出一个异常,用来提示用户,可能发生了并发修改。
因此当我们确实有需求需要删除其中一部分元素时,因该如java手册建议的那样使用Iterator进行操作。
private static void test() { List<String> names = new ArrayList<String>() {{ add("Hello"); add("World"); add("Good"); }}; Iterator iterator = names.iterator(); while (iterator.hasNext()) { if (iterator.next().equals("Hello")) { iterator.remove(); } } }
到此这篇关于Java增强for循环的增删操作的文章就介绍到这了,更多相关Java增强for循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!