先看一段代码
- List < Integer > list = new ArrayList < Integer > ();
- list.add(1);
- list.add(2);
- list.add(3);
- list.add(4);
- list.add(5);
- Iterator < Integer > it = list.iterator();
- Collections.sort(list);
- while (it.hasNext()) {
- System.out.println(it.next());
- }
Java7 运行效果
1 2 3 4 5
Java8 运行效果
结果分析
在上面的代码中, 我们先得到 list 的 iterator, 然后对 list 进行排序, 最后遍历 iterator
从 Java8 的错误信息中可以看出 it.next( ) 方法中检查 list 是否已经被修改, 由于在遍历之前进行了一次排序, 所以 checkForComodification 方法抛出异常 ConcurrentModificationException
这个可以理解, 因为排序, 肯定会修改 list
但是为啥 Java7 中没问题呢?
源码分析
首先看 checkForComodification 方法是如何判断的, 如下所示:
- final void checkForComodification() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- }
可以看出, 有两个内部成员变量用来判断是否发生了修改: modCount 和 expectedModCount
Iterator 中记录了 expectedModCount
List 中记录了 modCount
checkForComodification 方法通过比较 modCount 和 expectedModCount 来判断是否发生了修改
在 Java7 中, Collections.sort( list ) 调用的是 Collections 自身的 sort 方法, 如下所示:
- public static < T extends Comparable < ?super T >> void sort(List < T > list) {
- Object[] a = list.toArray();
- Arrays.sort(a);
- ListIterator < T > i = list.listIterator();
- for (int j = 0; j < a.length; j++) {
- i.next();
- i.set((T) a[j]);
- }
- }
可以看出, 该排序算法只是改变了 List 中元素的值 (i.set((T)a[j]);), 并没有修改 modCount 字段所以 checkForComodification 方法不会抛出异常
而在 Java8 中, Collections.sort( list ) 调用的是 ArrayList 自身的 sort 方法, 如下所示:
- public static < T extends Comparable < ?super T >> void sort(List < T > list) {
- list.sort(null);
- }
ArrayList 的 sort 方法实现如下:
可以看出最后一行, modCount++ 修改了 modCount 字段
所以 checkForComodification 方法会抛出异常
关于 Java8 中 Collections.sort 方法的修改
之前, Collection.sort 复制 list 中的元素以排序到数组中, 对数组进行排序, 然后使用数组中的元素更新列表, 并将默认方法 List.sort 推迟到 Collection.sort 这不是一个最佳的设计
从 8u20 发布起, Collection.sort 将推迟到 List.sort, 这意味着, 例如, 现有的以 ArrayList 实例调用 Collection.sort 的代码将使用由 ArrayList 实现的最佳排序
来源: http://www.jianshu.com/p/75b0a91bb6a8