被忽视的ArrayList,你知道多少
2019獨角獸企業重金招聘Python工程師標準>>>
我們對一些框架,并發,方案 狂熱追求的同時,往往有時候會忽略一些經常用到一些API 比如HashMap ,ArrayList等。
之前對ArrayList迭代刪除的同時遇到了一些問題,當時卻不了了之了,這種思想是不可取的,接下來我們看下ArrayList 操作過程當中可能遇到的問題,首先直接奉上代碼:
public class ArrayListTest {private static List<String> list = new ArrayList<>(Arrays.asList("a","b","c","d","e","f","g","h","i"));public static void main(String[] args) { // doTest1(); // doTest2(); // doTest3(); // doTest4();doTest5();}/*** ConcurrentModificationException*/public static void doTest1() {for (String str : list) {System.out.println(str);if (str.contains("b")) {list.remove(str);}}}/*** 成功*/public static void doTest2() {for(int i = 0 ; i< list.size() ; i++) {String s = list.get(i);if(s.contains("b")){list.remove(s);}}}/*** IndexOutOfBoundsException*/public static void doTest3() {int size = list.size();for(int i = 0 ; i< size ; i++) {String s = list.get(i);if(s.contains("b")){list.remove(s);}}}/*** 正常刪除*/public static void doTest4() {for(Iterator<String> iterator = list.iterator();iterator.hasNext();) {String next = iterator.next();System.out.println(next);if(next.contains("b")) {iterator.remove();}}}/*** ConcurrentModificationException*/public static void doTest5() {for (Iterator<String> ite = list.iterator(); ite.hasNext();) {String next = ite.next();if(next.contains("b")) {list.remove(next);}}} }方法一報錯:java.util.ConcurrentModificationException
方法二報錯:正常刪除,不推薦;每次循環都需計算list的大小,效率低
方法三報錯:下標越界 java.lang.IndexOutOfBoundsException
list移除了元素但size大小未響應變化,所以導致數組下標不對;
list.remove(i)必須size--
而且取出的數據的索引也不準確,同時需要做i--操作
方法四報錯:正常刪除,推薦使用
方法五報錯:java.util.ConcurrentModificationException
我們先針對上面的報錯,看下ArrayList的源碼:(add 和 remove)
ArrayList繼承AbstractList , modCount 是AbstractList中定義數組修改次數的元素。ArrayList繼承AbstractList,當調用ArrayList的add或remove方法時modCount++。
只對ArrayList進行操作,只會修改modCount 值并不會校驗。
ArrayList進行foreach時所調用的迭代器(內部迭代器Itr)
int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount;public boolean hasNext() {return cursor != size; }@SuppressWarnings("unchecked") public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i]; } final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException(); }expectedModCount? 在創建的時候進行的初始化,默認的時候兩者相等,ArrayList的增加,刪除,修改都會增加modCount的值。
ArrayList通過foreach進入它的內部循環迭代器Itr時,expectedModCount 就被賦值modCount,之后對ArrayList的增刪改操作,modCount會增加,但是expectedModCount 不會做同步更新,在調用Itr的next()方法時,會校驗兩者有沒有并發修改過(modCount != expectedModCount) 會拋出ConcurrentModificationException。
所以可證方法一 和 方法五 問題。
接下來看方法六
private static List<String> list = new ArrayList<>(Arrays.asList("a","b","c","d","e","f","g","h","i")); public static void doTest6() {for (Iterator<String> ite = list.iterator(); ite.hasNext();) {String next = ite.next();if(next.contains("h")) {list.remove(next);}}System.out.println(list);}沒報錯,并輸出了:[a, b, c, d, e, f, g, i]
public boolean hasNext() {return cursor != size; }Itr中 與next()方法游標相關,此處就不說了。
?
?
轉載于:https://my.oschina.net/LucasZhu/blog/1841639
總結
以上是生活随笔為你收集整理的被忽视的ArrayList,你知道多少的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PAT1096 Consecutive
- 下一篇: XML创建(1)