Fail-Fast 前奏
2017-11-05 17:15
106 查看
示例代码1
public static void main(String[] args) { String string = "a b c d e"; List<String> stringList = Arrays.asList(string.split(" ")); Iterator<String> iterator = stringList.iterator(); while (iterator.hasNext()) { if(iterator.next().equals("c")) { stringList.remove("c"); } } }
输出:
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.remove(AbstractList.java:161) at java.util.AbstractList$Itr.remove(AbstractList.java:374) at java.util.AbstractCollection.remove(AbstractCollection.java:293) at DotThis.main(DotThis.java:75)
报不支持的操作异常,UnsupportedOperationException。
ArrayList.asList返回的List是固定大小的List,也就是说不可以对其进行add、remove操作。
源码如下:
//Returns a fixed-size list backed by the specified array. @SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList(T... a) { return new ArrayList<>(a); } //该ArrayList类不是java.util包中的内容,而是Arrays类的内部类。 private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } /*省略此处代码*/ }
从上面代码的注释中可以看到是 “返回的是固定大小的List”。从源码实现上可以看到,private final E[] a; ,内部类ArrayList中的成员变量a,是final的。
示例代码二
public static void main(String[] args) { String string = "a b c d e"; List<String> arrList = Arrays.asList(string.split(" ")); List<String> stringList = new ArrayList<String>(arrList); Iterator<String> iterator = stringList.iterator(); while (iterator.hasNext()) { if(iterator.next().equals("c")) { stringList.remove("c"); } } }
输出:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) at DotThis.main(DotThis.java:76)
每个容器源码都会有modCount,modCount用来表示容器被结构性修改的次数。所谓结构性修改是指,改变了容器的size,或者在迭代过程中产生了不正确的结果。
代码中,在迭代到”c”时,stringList.remove(“c”); 执行了remove操作,对list造成了结构性修改,改变了list的size,modCount的值会加1。
这样当迭代到”d”时,发现expectedModCount与modCount不等了,因此抛ConcurrentModificationException异常了。
示例代码三
public static void main(String[] args) { String string = "a b c d e"; List<String> stringList1 = Arrays.asList(string.split(" ")); List<String> stringList = new ArrayList<String>(stringList1); System.out.println(stringList); Iterator<String> iterator = stringList.iterator(); while (iterator.hasNext()) { if(iterator.next().equals("c")) iterator.remove();//这里跟上例不同,上例为stringList.remove("c"); } } System.out.println(stringList); }
输出:
[a, b, c, d, e] [a, b, d, e]
查看ArrayList#Itr#remove方法:
private class Itr implements Iterator<E> { public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } /**省略此处代码**/ }
从上面代码可以看到,首先也判断了expectedModCount与modCount是否相等,但是这时还没有执行remove操作,因此不会抛异常。在执行了ArrayList.this.remove(lastRet); 之后,有一个关键的一行expectedModCount = modCount; 更新了expectedModCount的值。
相关文章推荐
- Java提高篇(三四)-----fail-fast机制
- Java提高篇(三四)-----fail-fast机制
- (转)java fail-fast机制
- fail-fast机制
- [转载] fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)
- Fail-Fast原则
- Java fail-fast机制
- Java提高篇(三四)-----fail-fast机制
- java中fail-fast 和 fail-safe的区别
- fast forward 讲解:利用gitub进行托管 之 git push错误 fail to push some refs——no fast forward
- java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制)
- Java中容器的迭代器的fail-fast机制
- 集合-fail-fast机制
- 快速失败(fail-fast)和安全失败(fail-safe)
- 关于快速报错fail-fast想说的之fail-fast的实现原理(一)
- java-----ArrayList的fail-fast机制学习
- Fail: Failover,Failfast,Failback,Failsafe
- Java 集合之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)
- Java集合(fail-fast机制)
- fail-fast/happens-before