List和Set集合中iterator的fail-fast特性之区别
来源:互联网 发布:域名com cn net的区别 编辑:程序博客网 时间:2024/05/16 16:20
刚才看到一个问题,关于List和Set集合中iterator的fail-fast特性
先上代码:
List集合:
public class Test {public static void main(String[] args){List<String> L = new LinkedList();L.add("aaa");L.add("bbb");L.add("ccc");System.out.println(L);String delete = "bbb";for(Iterator<String> iter=L.iterator();iter.hasNext();){String now = iter.next();System.out.println(now);if(now==delete)L.remove(delete);}System.out.println(L);}}
运行无异常,List在用iterator遍历过程中,可以用List的remove方法删除其最后两个元素任意一个(不能同时删除)
Set集合:
public class Test {public static void main(String[] args){Set<String> S = new LinkedHashSet();S.add("aaa");S.add("bbb");S.add("ccc");System.out.println(S);String delete = "bbb";for(Iterator<String> iter=S.iterator();iter.hasNext();){String now = iter.next();System.out.println(now);if(now==delete)S.remove(delete);}System.out.println(S);}}
当在用iterator遍历过程中,用Set的remove方法删除倒数第二个元素时运行出现异常:Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(Unknown Source)
at java.util.LinkedHashMap$LinkedKeyIterator.next(Unknown Source)
at nowcoder.Test.main(Test.java:18)
用Set的remove方法删除倒数第1个元素
public class Test {public static void main(String[] args){Set<String> S = new LinkedHashSet();S.add("aaa");S.add("bbb");S.add("ccc");System.out.println(S);String delete = "ccc";for(Iterator<String> iter=S.iterator();iter.hasNext();){String now = iter.next();System.out.println(now);if(now==delete)S.remove(delete);}System.out.println(S);}}运行正常:
[aaa, bbb, ccc]aaabbbccc[aaa, bbb]
终于到了解决问题的时候了。。。
1、首先找到List和Set各自的iterator实现源代码
List:LinkedList->AbstractSequentialList找到
/** * Returns an iterator over the elements in this list (in proper * sequence).<p> * * This implementation merely returns a list iterator over the list. * * @return an iterator over the elements in this list (in proper sequence) */ public Iterator<E> iterator() { return listIterator(); }</span>接着找。。。到AbstractList找到(由于太长,已删除无关代码)
/** * {@inheritDoc} * * <p>This implementation returns {@code listIterator(0)}. * * @see #listIterator(int) */ public ListIterator<E> listIterator() { return listIterator(0); }
public ListIterator<E> listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index); } private class Itr implements Iterator<E> { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; int expectedModCount = modCount; public boolean hasNext() { return cursor != size(); } public E next() { checkForComodification(); try { int i = cursor; E next = get(i); lastRet = i; cursor = i + 1; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } final void checkForComodification() {// if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { cursor = index; } }由上面代码可以看出当List用iterator遍历到倒数第二个元素时(已调用next方法),cursor=2,用remove方法删除会使得size()减1变为2,于是当iter调用hasNext方法时,cursor==size(),返回false,结束遍历,无异常。
当List用iterator遍历到倒数第一个元素时(已调用next方法),cursor=3,用remove方法删除会使得size()减1变为2,于是当iter调用hasNext方法时,cursor!=size(),本应返回true,返回的却是false???结束遍历,无异常。我也不知为什么。。。求解
Set:寻找路径:LinkHashSet->HashSet
public Iterator<E> iterator() { return map.keySet().iterator(); }
->HashMap$KeySet->HasMap$KeyIterator
final class KeyIterator extends HashIterator implements Iterator<K> { public final K next() { return nextNode().key; } }
->HashMap$HashIterator
abstract class HashIterator { Node<K,V> next; // next entry to return Node<K,V> current; // current entry int expectedModCount; // for fast-fail int index; // current slot HashIterator() { expectedModCount = modCount; Node<K,V>[] t = table; current = next = null; index = 0; if (t != null && size > 0) { // advance to first entry do {} while (index < t.length && (next = t[index++]) == null);//指向第一个不为空的元素 } } public final boolean hasNext() { return next != null; } final Node<K,V> nextNode() { Node<K,V>[] t; Node<K,V> e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null);//<span style="font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;">指向下一个不为空的元素</span> } return e; } public final void remove() { Node<K,V> p = current; if (p == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); current = null; K key = p.key; removeNode(hash(key), key, null, false, false); expectedModCount = modCount; } }
从上面代码中可以看出,当Set用iterator遍历到倒数第二个元素时(已调用next方法),next(Node类型)指向倒数一个元素(节点),不为null,用remove方法删除会使得modCount加一而expectedModCount不变,于是
modCount = expectedModCount+1 =》 modCount != expectedModCount
当iter调用hasNext方法时,next!=null ,返回true,调用next方法,即调用nextNode方法,抛出异常。
如果是在遍历到倒数第一个元素时,next=null,所以无论你干什么都可以,反正下一次hasNext会返回false。
这样看来,只要不是在遍历倒数第一个元素时,修改Set,都会使得modCount != expectedModCount,从而抛出异常。
- List和Set集合中iterator的fail-fast特性之区别
- java中fail-fast 和 fail-safe的区别
- java中fail-fast 和 fail-safe的区别
- java中fail-fast 和 fail-safe的区别
- java中fail-fast 和 fail-safe的区别
- java中fail-fast 和 fail-safe的区别
- java中fail-fast 和 fail-safe的区别
- java中fail-fast 和 fail-safe的区别
- Iterator的fail-fast
- List和Set中Iterator的next()用法的区别
- set集合和 list集合 的区别
- set集合和list集合的区别
- set集合和list集合的区别
- Java中Vector、List、Set集合、Iterator迭代器的使用
- Java中Vector、List、Set集合、Iterator迭代器的使用
- java 中list,set,map集合的用法和区别
- java 中list,set,map集合的用法和区别
- 集合之List、Map、Set的区别
- DA1458x使用之第二篇——PWM
- git check
- MySQL error 1042解决
- ImageIcon icon 相对路径设置
- 运用std::string 实现split功能
- List和Set集合中iterator的fail-fast特性之区别
- Leetcode 74. Search a 2D Matrix 2D矩阵查找 解题报告
- web.xml 中的过滤器(拦截器)Filter与监听器Listener的作用和区别?
- POJ 1946 DP
- Android Fragment应用及原理
- Github学习之EasyTabs打造绚丽TabLayout+ViewPager滑动动画集合库
- Codeforces Round #353 (Div. 2) C 思维
- 引导页圆点的滑动两种实现方式
- c3p0连接数据库失败No suitable driver