91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么移除List中的元素

發布時間:2021-10-20 10:07:14 來源:億速云 閱讀:201 作者:iii 欄目:編程語言

本篇內容主要講解“怎么移除List中的元素”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么移除List中的元素”吧!

一、異常代碼

我們先看下這段代碼,你有沒有寫過類似的代碼

public static void main(String[] args) {

  List<Integer> list = new ArrayList<>();

  System.out.println("開始添加元素 size:" + list.size());

  for (int i = 0; i < 100; i++) {
    list.add(i + 1);
  }

  System.out.println("元素添加結束 size:" + list.size());

  Iterator<Integer> iterator = list.iterator();

  while (iterator.hasNext()) {
    Integer next = iterator.next();
    if (next % 5 == 0) {
      list.remove(next);
    }
  }
  System.out.println("執行結束 size:" + list.size());
}
 

「毫無疑問,執行這段代碼之后,必然報錯,我們看下報錯信息。」

怎么移除List中的元素  

我們可以通過錯誤信息可以看到,具體的錯誤是在checkForComodification 這個方法產生的。

 

二、ArrayList源碼分析

首先我們看下ArrayListiterator這個方法,通過源碼可以發現,其實這個返回的是ArrayList內部類的一個實例對象。

public Iterator<E> iterator() {
  return new Itr();
}
 

我們看下Itr類的全部實現。

private class Itr implements Iterator<E> {
  int cursor;       // index of next element to return
  int lastRet = -1; // index of last element returned; -1 if no such
  int expectedModCount = modCount;

  Itr() {}

  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];
  }

  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();
    }
  }

  @Override
  @SuppressWarnings("unchecked")
  public void forEachRemaining(Consumer<? super E> consumer) {
    Objects.requireNonNull(consumer);
    final int size = ArrayList.this.size;
    int i = cursor;
    if (i >= size) {
      return;
    }
    final Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length) {
      throw new ConcurrentModificationException();
    }
    while (i != size && modCount == expectedModCount) {
      consumer.accept((E) elementData[i++]);
    }
    // update once at end of iteration to reduce heap write traffic
    cursor = i;
    lastRet = i - 1;
    checkForComodification();
  }

  final void checkForComodification() {
    if (modCount != expectedModCount)
      throw new ConcurrentModificationException();
  }
}
 

「參數說明:」

cursor : 下一次訪問的索引;

lastRet :上一次訪問的索引;

expectedModCount :對ArrayList修改次數的期望值,初始值為modCount

modCount :它是AbstractList的一個成員變量,表示ArrayList的修改次數,通過addremove方法可以看出;

「幾個常用方法:」

hasNext():

public boolean hasNext() {
 return cursor != size;
}
 

如果下一個訪問元素的下標不等于size,那么就表示還有元素可以訪問,如果下一個訪問的元素下標等于size,那么表示后面已經沒有可供訪問的元素。因為最后一個元素的下標是size()-1,所以當訪問下標等于size的時候必定沒有元素可供訪問。

next()

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];
}
 

注意下,這里面有兩個非常重要的地方,cursor初始值是0,獲取到元素之后,cursor 加1,那么它就是下次索要訪問的下標,最后一行,將i賦值給了lastRet這個其實就是上次訪問的下標。

此時,cursor變為了1,lastRet變為了0。

最后我們看下ArrayListremove()方法做了什么?

public boolean remove(Object o) {
  if (o == null) {
    for (int index = 0; index < size; index++)
      if (elementData[index] == null) {
        fastRemove(index);
        return true;
      }
  } else {
    for (int index = 0; index < size; index++)
      if (o.equals(elementData[index])) {
        fastRemove(index);
        return true;
      }
  }
  return false;
}
 
private void fastRemove(int index) {
  modCount++;
  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 work
}
 

「重點:」

我們先記住這里,modCount初始值是0,刪除一個元素之后,modCount自增1,接下來就是刪除元素,最后一行將引用置為null是為了方便垃圾回收器進行回收。

 

三、問題定位

到這里,其實一個完整的判斷、獲取、刪除已經走完了,此時我們回憶下各個變量的值:

cursor : 1(獲取了一次元素,默認值0自增了1);

lastRet :0(上一個訪問元素的下標值);

expectedModCount :0(初始默認值);

modCount :1(進行了一次remove操作,變成了1);

不知道你還記不記得,next()方法中有兩次檢查,如果已經忘記的話,建議你往上翻一翻,我們來看下這個判斷:

final void checkForComodification() {
  if (modCount != expectedModCount)
    throw new ConcurrentModificationException();
}
 

modCount不等于expectedModCount的時候拋出異常,那么現在我們可以通過上面各變量的值發現,兩個變量的值到底是多少,并且知道它們是怎么演變過來的。那么現在我們是不是清楚了ConcurrentModificationException異常產生的愿意呢!

「就是因為,list.remove()導致modCountexpectedModCount的值不一致從而引發的問題。」

 

四、解決問題

我們現在知道引發這個問題,是因為兩個變量的值不一致所導致的,那么有沒有什么辦法可以解決這個問題呢!答案肯定是有的,通過源碼可以發現,Iterator里面也提供了remove方法。

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();
  }
}
 

你看它做了什么,它將modCount的值賦值給了expectedModCount,那么在調用next()進行檢查判斷的時候勢必不會出現問題。

那么以后如果需要remove的話,千萬不要使用list.remove()了,而是使用iterator.remove(),這樣其實就不會出現異常了。

public static void main(String[] args) {

  List<Integer> list = new ArrayList<>();

  System.out.println("開始添加元素 size:" + list.size());

  for (int i = 0; i < 100; i++) {
    list.add(i + 1);
  }

  System.out.println("元素添加結束 size:" + list.size());

  Iterator<Integer> iterator = list.iterator();

  while (iterator.hasNext()) {
    Integer next = iterator.next();
    if (next % 5 == 0) {
      iterator.remove();
    }
  }
  System.out.println("執行結束 size:" + list.size());
}

「建議:」

另外告訴大家,我們在進行測試的時候,如果找不到某個類的實現類,因為有時候一個類有超級多的實現類,但是你不知道它到底調用的是哪個,那么你就通過debug的方式進行查找,是很便捷的方法。

到此,相信大家對“怎么移除List中的元素”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新乡市| 修武县| 甘南县| 双柏县| 大化| 中西区| 民乐县| 措美县| 拉萨市| 吉首市| 黑河市| 丰镇市| 甘泉县| 余江县| 昔阳县| 略阳县| 郓城县| 墨玉县| 壶关县| 鱼台县| 永新县| 平乐县| 阳泉市| 宁陵县| 呈贡县| 志丹县| 甘肃省| 云和县| 叙永县| 册亨县| 清新县| 黄石市| 沂水县| 静海县| 临潭县| 桃源县| 寿光市| 顺平县| 兴宁市| 和顺县| 金溪县|