先看一段代碼
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> it = list.iterator();
Collections.sort(list);
while (it.hasNext()) {
System.out.println(it.next());
}
Java7 運作效果
1
2
3
Java8 運作效果
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuYWOxkjNzcDM0YTOyQWOmZ2NyYTM5QjMjRzY1IzNyQjMfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
結果分析
在上面的代碼中,我們先得到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實作的最佳排序