日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

被忽视的ArrayList,你知道多少

發布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 被忽视的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++。

public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true; }private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity); } public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its workreturn oldValue; }

只對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,你知道多少的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。