1. 程式人生 > >Java 中list(ArrayList)的foreach遍歷方式呼叫list的remove刪除元素,不丟擲ConcurrentModificationException

Java 中list(ArrayList)的foreach遍歷方式呼叫list的remove刪除元素,不丟擲ConcurrentModificationException

關於list刪除元素的當時有很多,具體可以參考下面這個部落格。

https://blog.csdn.net/claram/article/details/53410175

裡面提到了list的foreach遍歷方式刪除元素,會丟擲ConcurrentModificationException。foreach是迭代器遍歷的一種簡寫。
但是,如果list中只有兩個元素,刪除第一個元素時,則不會丟擲ConcurrentModificationException異常。

首先看一下迭代器的hasNext()next()方法原始碼。

        public boolean hasNext() {
        // 當前元素的位置不等於list的size代表還有元素沒有遍歷
return cursor != size; } @SuppressWarnings("unchecked") public E next() { //檢查是否有迭代器之外的modify 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() { //expectedModCount 是迭代器自己維護的變數 //modCount 是list中元素修改的數量
//如果呼叫迭代器的方法對list操作,二者是相等的。例如下面的remove方法 if (modCount != expectedModCount) throw new ConcurrentModificationException(); } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; //保證expectedModCount和modCount相等 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }

在看一下ArrayList的remove方法。

    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++
        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
    }

假設ArrayList只有兩個元素,刪除第一個元素的程式碼如下:

    public static void main(String []args) {
        List<String> list = new ArrayList<>();
        list.add("ddd");
        list.add("aaa");
        for (String string : list) {
            if (string.equals("aaa")) {
                list.remove(string);
            }
            System.out.println(string);
        }
    }

上面程式碼並沒有丟擲任何異常,關鍵在於迭代器遍歷第一個元素後,此時cursor=1,modCount=expectedModCount=2,size=2;
刪除第一個元素後,cursor=1,modCount=3,expectedModCount=2,size=1;
繼續執行迭代器的hasNext()時,發現cursor==size==1,迭代器認為已經遍歷結束。並沒有繼續執行next函式,還沒有來得及執行checkForComodification()迴圈已經結束。

總結
在這種特殊情況下,雖然此時並沒有丟擲異常,但是也沒有按照我們的預想,將兩個元素全部遍歷完,只遍歷了一個元素就結束了,在刪除元素時,還應當使用迭代器更加安全。

相關推薦

Java list(ArrayList)的foreach方式呼叫list的remove刪除元素ConcurrentModificationException

關於list刪除元素的當時有很多,具體可以參考下面這個部落格。 https://blog.csdn.net/claram/article/details/53410175 裡面提到了list的foreach遍歷方式刪除元素,會丟擲ConcurrentMo

JavaList集合的(三種方式效率的比較)

public static void main(String args[]){ compare(); } public static void compare() { List<String> list = new ArrayList

JavaList集合的

java list 集合 遍歷 一、對List的遍歷有三種方式 List<String> list = new ArrayList<String>(); list.add("testone"); list.add(

Javalist如何利用進行刪除操作

Java三種遍歷如何進行list的便利刪除:1、for迴圈:常見初五寫法:(由於下標問題達不到想要效果)for(int i=0;i<list.size();i++){ if(list.get(i).equals("del")) list.remo

javaMap,兩種方式

package cn.mdln.study3; import java.util.Map; import java.util.Set; import java.util.Iterator; import java.util.HashMap; /**  * Map,兩種遍歷方

AndroidList循環性能對照

最快 next() num trac () ren length iter pan 在android開發中僅僅要是列表式風格界面我們差點兒都須要用到List來存放數據,在數量非常少的List的話差點兒不論什麽一種循環遍歷方式總體性能都無區別。可是當我們遇

javaSet集合的方法

基本數據類型 對象 叠代器 比較 for hashset 循環 sta ins S兒童集合的遍歷: 第一種:for增強循環 Set<String> set = new HashSet<String>(); for (String str : set

總結下List和Map方式(日常總結)

一.Map   public static void main(String[] args) { Map<Integer, Integer> map = new HashMap<>(); map.put(1, 2);

java集合的三種方式以及各自優缺點分析

1、Iterator介面 Iterator是Java集合框架的成員,主要用於遍歷(即迭代訪問)Collection集合中的元素,也稱為迭代器。 提供的三種方法: boolean hasNext():返回集合裡的下一個元素。 Object next():

Java使用size()方法PriorityQueue出現元素全的問題

在使用PriorityQueue類時 使用 for(int i=0; i<priorityqueue.size(); i++) 與 for(int i : priorityqueue) 遍歷PriorityQueue時 有時會出現PriorityQueue未能正常排序

javaSet集合的及實現類比較分析

java中Set集合是一個不包含重複元素的Collection,首先我們先看看遍歷方法 package com.sort; import java.util.HashSet; import java.util.Iterator; import java.util.Set;

vue.js的兩種方式(以及substring,split,getJsonLength)

第一種: $.each($('.active'), function(index, item){ attrTxt+= (' ' + $(item).text()); attrid

Vuev-for多層巢狀資料能重新渲染的問題

問題 { "properties": [ [ { "name": "property_name", "example": "travel_time", "value": "" }, { "name":

JavaList集合的三種方式

asn tex iter for nbsp next next() ray string 首先創建一個List集合: List<String> list = new ArrayList<String>();list.add("name"); list

Java(8)List方式

system pack map 新建 lam entry lambda googl list() ============Java8之前的方式==========Map<String, Integer> items = new HashMap<>()

Java集合類set、List和map的方式

Java中集合類的遍歷方式 Java中集合分為set、List和map。 1.set集合 set集合常用的有兩種遍歷方式: Set<String>  set = new HashSet<String>(); 第一種利用for迴圈: for(S

Java ListArrayList) 的五種例子

package Strings; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Lists {     public static vo

Java使用foreachlist的盲點

我們通常在專案中會用到ArrayList ,喜歡使用jdk1.5以後的foreach進行對list集合遍歷,但是以下的操作會遇到小坑請看程式碼:public class TestListUtils {

javaList、Set、Map集合的幾種方式小結和比較

一、集合類的通用遍歷方式, 用迭代器迭代:1.迭代遍歷whileIterator it = list.iterator();while(it.hasNext()){Object obj = it.next();System.out.println(it.next());}2.