Java增强for遍历LinkedList所引发的思考
来源:互联网 发布:万国数据怎么样 编辑:程序博客网 时间:2024/06/06 16:45
上一篇我比较了普通for和增强for之间的区别,效率和应用场景。但其中有一个问题引发了我的思考。就是网上都说用增强for遍历LinkedList会出现ConcurrentModificationException,然而我写的代码却不会出现,我的代码如下:
LinkedList<String> list = new LinkedList<>(); list.add("sky_100"); list.add("a"); list.add("b"); list.add("c"); for (String str : list) { if ("b".equals(str)) list.remove(str); } for(String str: list){ System.out.println(str); }
运行结果:
没报错呀,难道网上说的都是错的?顿时有种众人皆醉我独醒的感觉,哈哈。想想还是多试几下,确认比较好,于是我又试了一段代码:
LinkedList<String> list = new LinkedList<>(); list.add("sky_100"); list.add("a"); list.add("b"); list.add("c"); for (String str : list) { if ("a".equals(str)) list.remove(str); } for (String str : list) { System.out.println(str); }
没改动什么,就是把if判断把“b”改成了“a”;
运行结果:
真是有意思,接下来就来解释原因吧:
首先来看这段出错代码反编译后的源码:
LinkedList linkedlist = new LinkedList(); linkedlist.add("sky_100"); linkedlist.add("a"); linkedlist.add("b"); linkedlist.add("c"); Iterator iterator = linkedlist.iterator(); do { if (!iterator.hasNext()) break; String s = (String)iterator.next(); if ("a".equals(s)) linkedlist.remove(s); } while (true); String s1; for (Iterator iterator1 = linkedlist.iterator(); iterator1.hasNext(); System.out.println(s1)) s1 = (String)iterator1.next();
经过调试和查看LinkedList源码发现:每次调用next()方法时会做判断,源码如下:
public E next() { checkForComodification(); if (!hasNext()) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; return lastReturned.item; }
再看checkForComodification()方法源码:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
这两个方法都是LinkedList的内部类ListItr的方法,原来当modCount 和expectedModCount不相等时会抛出异常。那这两个数为什么会不相等呢,答案是在调用remove()方法的时候改了modCount的值,口说无凭,源码为证:
public boolean remove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; }
remove调用了unlink()方法,看看unlink()源码:
E unlink(Node<E> x) { ...... x.item = null; size--; <span style="color:#F00">modCount++;</span> return element; }
哈哈,找出来了,那么问题来了,既然每次移除后modCount都会改变,而每次next()都会检查,按理说每次remove后都会报错,为啥我第一次的不会报错呢,答案是:因为“b”在倒数第二个元素,每次调用方法hasNext()的时候
public boolean hasNext() { return nextIndex < size; }
判断的是nextIndex是否小于当前集合的大小,然而在调用remove()时:在remove调用了unlink方法,上面讲过了,而unlink方法中
E unlink(Node<E> x) { ...... x.item = null; <span style="color:#F00">size--;</span> modCount++; return element; }
所以这下明白了吧,当删出“b”的时候,集合的大小已经变为3了,当调用hasNext()时
public boolean hasNext() { return nextIndex < size;//return 3<3 }
返回的是false,根本没机会去调用next()方法检查modCount 和expectedModCount是否相等。
好了,问题解决了,开心!
启发,遇到问题多从源码中找答案,既可以增加自己阅读代码的能力,又让自己的答案十分可信,因为那就是权威,比任何网上说的都有效。
- Java增强for遍历LinkedList所引发的思考
- 【Java】集合遍历增强for和普通for的区别
- 一个函数命名所引发的思考
- java ArrayList与LinkedList的普通for循环遍历
- 关于Java增强for循环的一点儿思考
- JAVA-OPTS引发的思考
- Java正则引发的思考
- JAVA注解引发的思考
- JAVA注解引发的思考
- 你真的了解For循环吗?一道For循环Java面试题引发的思考
- 你真的了解For循环吗?一道For循环Java面试题引发的思考
- 两道面试题所引发的C指针的思考
- 由一份auto_ptr源代码所引发的思考
- 由孩子不叫人所引发的思考
- 由一份auto_ptr源代码所引发的思考
- jdk安装和环境变量所引发的思考
- java的增强型for与js的for遍历数组
- 增强For遍历Map集合的要点!
- [PAT]1007. Maximum Subsequence Sum (25)@Java
- view group adapter的封装
- 从尾到头打印链表java实现
- 【二叉树】637. Average of Levels in Binary Tree
- Dom和sax解析的比较
- Java增强for遍历LinkedList所引发的思考
- Java程序猿快速上手PHP
- 使用openswan搭建ipsec vpn
- 1207:水仙花数
- 【qt】QT5.7.0+opencv2.4.9配置
- Android录制视频示例
- C#的Winform窗体之间的传值
- centos永久修改hostname
- 如何在jsp上查询并显示数据库mysql的数据表格