欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?ArrayList實現(xiàn)刪除指定位置的元素

 更新時間:2023年01月09日 09:16:33   作者:海棠路  
目標(biāo):list中有0到39共40個元素,刪除其中索引是10、20、30的元素。本文為大家整理了三個不同的方法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

目標(biāo):list中有0到39共40個元素,刪除其中索引是10、20、30的元素

方案一:使用普通for循環(huán)從前往后遍歷再刪除

//初始化List列表
List<String> list = new ArrayList<>();
for (int i = 0; i < 40; i++) {
    list.add("element" + i);
}

首先當(dāng)我們刪除第10位元素時,List會將后面的元素向前補位,之后再查第10位元素就會輸出第11位元素

for (int i = 0; i < list.size(); i++) {
    if (i == 10) {
        list.remove(i);
    }
}
System.out.println(list.get(10));

輸出:

element11

那么刪除了一個元素以后,后面需要刪除的元素位置就向前提1位

/**
 * 如果明確需要刪除元素的位置
 * 那么可以這樣,每刪除一個元素后就把下一個要刪除元素的位置減1
 * 注意這么做有個需要注意的點,那就是每次刪除完節(jié)點后遍歷指針i需要減一,這樣在刪除兩個臨近節(jié)點時才不會出現(xiàn)問題
 * 比如要刪除10和11
 */
for (int i = 0; i < list.size(); i++) {
    if (i == 10) {
        list.remove(i);
        i--;
    }
    if (i == 19) {
        list.remove(i);
        i--;
    }
    if (i == 28) {
        list.remove(i);
        i--;
    }
}

System.out.println(list.contains("element10"));
System.out.println(list.contains("element20"));
System.out.println(list.contains("element30"));

輸出:

 false
 false
 false

當(dāng)然我們可以用一個數(shù)組或列表從小到大存儲需要刪除的位置,然后再for循環(huán)中進(jìn)行運算和取值

方案二:使用普通for循環(huán)從后往前遍歷再刪除

從后向前遍歷的好處是我們不需要再像方案一一樣每刪除一個元素都需要去考慮后面元素向前補位的問題

for (int i = list.size() - 1; i >= 0; i--) {
    if (i == 30) {
        list.remove(i);
    }
    if (i == 20) {
        list.remove(i);
    }
    if (i == 10) {
        list.remove(i);
    }
}
System.out.println(list.contains("element10"));
System.out.println(list.contains("element20"));
System.out.println(list.contains("element30"));

輸出:

 false
 false
 false

從后向前,即使后面進(jìn)行元素進(jìn)行向前補位操作也不會影響前面需要刪除的元素

這里也可以用一個數(shù)組或列表存儲需要刪除的元素,從大到小排列,取出一個刪除一個

方案三:使用迭代器刪除

Iterator<String> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    String next = iterator.next();
    if (i == 10) {
        iterator.remove();
    }
    i++;
}
System.out.println(list.get(10));
System.out.println(list.contains("element10"));

輸出:

element11
false

在迭代器中維護(hù)一個數(shù)字i標(biāo)識遍歷的位置

如果我們在迭代器中繼續(xù)刪除另外20和30位置元素

Iterator<String> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    String next = iterator.next();
    if (i == 10) {
        iterator.remove();
    }
    if (i == 20) {
        iterator.remove();
    }
    if (i == 30) {
        iterator.remove();
    }
    i++;
}
System.out.println(list.get(10));
System.out.println(list.contains("element10"));
System.out.println(list.get(20));
System.out.println(list.contains("element20"));
System.out.println(list.get(30));
System.out.println(list.contains("element30"));

輸出:

element11
false
element22
false
element33
false

首先我們在迭代過程中指定的是刪除10、20、30三個位置的元素,可以看到輸出contains時都是false表示正確刪除,但是最終輸出列表的值發(fā)現(xiàn)對應(yīng)索引位置已經(jīng)進(jìn)行了補位。

我們debug分析一下為什么

先簡單介紹一下Iterator和Iterable

Iterable是一個迭代接口,實現(xiàn)了這個接口代表該類可以迭代

可以看到我們的集合Collection接口就是它的子類

它有一個主要方法:

// 返回一個實現(xiàn)了Iterator接口的對象,我們也是用這個對象去進(jìn)行迭代
Iterator<T> iterator();

Iterator,它主要有三個方法:

// 返回是否還有下一個元素
boolean hasNext();
// 返回下一個元素
E next();
// 刪除該元素
default void remove() {
    throw new UnsupportedOperationException("remove");
}

每個不同的集合類都會有不同的Iterator接口實現(xiàn),在ArrayList中使用了一個內(nèi)部類來實現(xiàn)

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

我們通過list.iterator()拿到的就是這個內(nèi)部類的對象實例,這個類中有兩個字段cursor和lastRet,這兩個字段就是我們能在迭代器中正確刪除對應(yīng)位置的元素的關(guān)鍵。

有關(guān)expectedModCount和modCount的問題后面會補充,我們先不用關(guān)注

cursor初始化是0 lastRet初始化是-1

分析next和remove方法的源碼

/**
* 可以先不關(guān)注這兩個Exception
* 每次調(diào)用next() cursor都會+1 而lastRet就會變成之前cursor的值
* cursor初始化是0
* lastRet初始化是-1
* 調(diào)用一次以后  cursor是1 lastRet變成0
**/
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 {
        // 調(diào)用本身的remove方法
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

關(guān)鍵是這個remove方法對cursor和lastRet的修改

假如正在刪除第10個元素

執(zhí)行remove方法前cursor應(yīng)該是11,lastRet是10

執(zhí)行了以后lastRet變成了-1,cursor變成了10

下次執(zhí)行next()方法返回的元素其實還是elementData[10]也就是List補位后正確的下一個元素,cursor變成了11,lastRet是10

總結(jié):使用迭代器遍歷時ArrayList會用lastRet和cursor兩個變量來維護(hù)當(dāng)前遍歷的元素索引和下一次需要遍歷元素的索引,通過這兩個變量就可以實現(xiàn)迭代中正確的刪除某個位置的元素。

到此這篇關(guān)于Java ArrayList實現(xiàn)刪除指定位置的元素的文章就介紹到這了,更多相關(guān)Java ArrayList刪除指定位置元素內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring?Boot自定義Starter組件開發(fā)實現(xiàn)配置過程

    Spring?Boot自定義Starter組件開發(fā)實現(xiàn)配置過程

    SpringBoot中的starter是一種非常重要的機制,能夠拋棄以前繁雜的配置,將其統(tǒng)一集成進(jìn)?starter,應(yīng)用者只需要在maven中引入starter依賴,這篇文章主要介紹了Spring?Boot自定義Starter組件開發(fā)實現(xiàn),需要的朋友可以參考下
    2022-06-06
  • JavaWeb實現(xiàn)文件上傳與下載的方法

    JavaWeb實現(xiàn)文件上傳與下載的方法

    這篇文章主要介紹了JavaWeb實現(xiàn)文件上傳與下載的方法的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • Java 使用Thumbnails對大圖片壓縮

    Java 使用Thumbnails對大圖片壓縮

    這篇文章主要介紹了Java 使用Thumbnails對大圖片壓縮,幫助大家更好的利用Java處理圖片,感興趣的朋友可以了解下
    2020-11-11
  • Springboot之整合Socket連接案例

    Springboot之整合Socket連接案例

    這篇文章主要介紹了Springboot之整合Socket連接案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • Java 隨機生成驗證碼(支持大小寫字母、數(shù)字、隨機字體)的實例

    Java 隨機生成驗證碼(支持大小寫字母、數(shù)字、隨機字體)的實例

    java隨機產(chǎn)生驗證碼,可以隨機生成數(shù)字、大寫字母、小寫字母。還可以隨機生成文字字體、及大小。在圖片上面可能字體都不不同、大小不等
    2013-05-05
  • Java實現(xiàn)登錄密碼強度校驗的項目實踐

    Java實現(xiàn)登錄密碼強度校驗的項目實踐

    本文主要介紹了Java實現(xiàn)登錄密碼強度校驗的項目實踐,包括使用正則表達(dá)式匹配校驗和密碼強度校驗工具類這兩種方法,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Redis緩存實例分步詳解

    Redis緩存實例分步詳解

    實際開發(fā)中緩存處理是必須的,不可能我們每次客戶端去請求一次服務(wù)器,服務(wù)器每次都要去數(shù)據(jù)庫中進(jìn)行查找,為什么要使用緩存?說到底是為了提高系統(tǒng)的運行速度
    2023-04-04
  • JAVA遞歸與非遞歸實現(xiàn)斐波那契數(shù)列

    JAVA遞歸與非遞歸實現(xiàn)斐波那契數(shù)列

    這篇文章主要為大家詳細(xì)介紹了JAVA遞歸與非遞歸實現(xiàn)斐波那契數(shù)列,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • List轉(zhuǎn)換成Map工具類的簡單實例

    List轉(zhuǎn)換成Map工具類的簡單實例

    下面小編就為大家?guī)硪黄狶ist轉(zhuǎn)換成Map工具類的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Spring Boot Admin實踐詳解

    Spring Boot Admin實踐詳解

    在本篇文章里小編給大家整理了關(guān)于Spring Boot Admin實踐的相關(guān)知識點,有需要的朋友們可以學(xué)習(xí)下。
    2019-12-12

最新評論