一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java List的remove()方法踩坑

Java List的remove()方法踩坑

2022-03-07 13:02倚樓聽風(fēng)雨 Java教程

Java的List在刪除元素時,一般會用list.remove(o)/remove(i)方法。在使用時,容易觸碰陷阱,本文就來介紹一下容易踩的坑,感興趣的可以了解一下

Java的List在刪除元素時,一般會用list.remove(o)/remove(i)方法。在使用時,容易觸碰陷阱,得到意想不到的結(jié)果。總結(jié)以往經(jīng)驗,記錄下來與大家分享。

首先初始化List,代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.cicc.am.test;
 
import java.util.ArrayList;
import java.util.List;
 
public class ListTest {
 
 public static void main(String[] args) {
  List<Integer> list=new ArrayList<Integer>();
  list.add(1);
  list.add(2);
  list.add(3);
  list.add(3);
  list.add(4);
  System.out.println(list);
 }
}

輸出結(jié)果為[1, 2, 3, 3, 4]

1、普通for循環(huán)遍歷List刪除指定元素--錯誤!!!

?
1
2
3
4
for(int i=0;i<list.size();i++){
   if(list.get(i)==3) list.remove(i);
}
System.out.println(list);

輸出結(jié)果:[1, 2, 3, 4]

為什么元素3只刪除了一個?本以為這代碼再簡單不過,可還是掉入了陷阱里,上面的代碼這樣寫的話,元素3是過濾不完的。只要list中有相鄰2個相同的元素,就過濾不完。List調(diào)用remove(index)方法后,會移除index位置上的元素,index之后的元素就全部依次左移,即索引依次-1要保證能操作所有的數(shù)據(jù),需要把index-1,否則原來索引為index+1的元素就無法遍歷到(因為原來索引為index+1的數(shù)據(jù),在執(zhí)行移除操作后,索引變成index了,如果沒有index-1的操作,就不會遍歷到該元素,而是遍歷該元素的下一個元素)。

  如果這樣,刪除元素后同步調(diào)整索引或者倒序遍歷刪除元素,是否可行呢?

2、for循環(huán)遍歷List刪除元素時,讓索引同步調(diào)整--正確!

?
1
2
3
4
for(int i=0;i<list.size();i++){
   if(list.get(i)==3) list.remove(i--);
}
System.out.println(list);

輸出結(jié)果:[1, 2, 4]

3、倒序遍歷List刪除元素--正確!

?
1
2
3
4
5
6
for(int i=list.size()-1;i>=0;i--){
 if(list.get(i)==3){
  list.remove(i);
 }
}
System.out.println(list);

輸出結(jié)果:[1, 2, 4]

4、foreach遍歷List刪除元素--錯誤!!!

?
1
2
3
4
for(Integer i:list){
    if(i==3) list.remove(i);
}
System.out.println(list);

拋出異常:java.util.ConcurrentModificationException

foreach 寫法實際上是對的 Iterable、hasNext、next方法的簡寫。因此從List.iterator()源碼著手分析,跟蹤iterator()方法,該方法返回了 Itr 迭代器對象。

?
1
2
3
public Iterator<E> iterator() {
      return new Itr();
  }

Itr 類定義如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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;
 
        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();
            }
        }
 
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

通過代碼我們發(fā)現(xiàn) Itr 是 ArrayList 中定義的一個私有內(nèi)部類,在 next、remove方法中都會調(diào)用checkForComodification 方法,該方法的 作用是判斷 modCount != expectedModCount是否相等,如果不相等則拋出ConcurrentModificationException異常。每次正常執(zhí)行 remove 方法后,都會對執(zhí)行expectedModCount = modCount賦值,保證兩個值相等,那么問題基本上已經(jīng)清晰了,在 foreach 循環(huán)中

執(zhí)行 list.remove(item);,對 list 對象的 modCount 值進(jìn)行了修改,而 list 對象的迭代器的 expectedModCount 值未進(jìn)行修改,因此拋出了ConcurrentModificationException異常。

5、迭代刪除List元素--正確!

java中所有的集合對象類型都實現(xiàn)了Iterator接口,遍歷時都可以進(jìn)行迭代:

?
1
2
3
4
5
6
7
Iterator<Integer> it=list.iterator();
 while(it.hasNext()){
  if(it.next()==3){
   it.remove();
  }
        }
System.out.println(list);

輸出結(jié)果:[1, 2, 4]

Iterator.remove() 方法會在刪除當(dāng)前迭代對象的同時,會保留原來元素的索引。所以用迭代刪除元素是最保險的方法,建議大家使用List過程

中需要刪除元素時,使用這種方式。

6、迭代遍歷,用list.remove(i)方法刪除元素--錯誤!!!

?
1
2
3
4
5
6
7
8
Iterator<Integer> it=list.iterator();
 while(it.hasNext()){
  Integer value=it.next();
   if(value==3){
   list.remove(value);
  }
 }
System.out.println(list);

拋出異常:java.util.ConcurrentModificationException,原理同上述方法4.

7、List刪除元素時,注意Integer類型和int類型的區(qū)別.

上述Integer的list,直接刪除元素2,代碼如下:

?
1
2
list.remove(2);
System.out.println(list);

輸出結(jié)果:[1, 2, 3, 4]

可以看出,List刪除元素時傳入數(shù)字時,默認(rèn)按索引刪除。如果需要刪除Integer對象,調(diào)用remove(object)方法,需要傳入Integer類型,代碼如下:

?
1
2
list.remove(new Integer(2));
System.out.println(list);

輸出結(jié)果:[1, 3, 3, 4]

總結(jié):

   1、用for循環(huán)遍歷List刪除元素時,需要注意索引會左移的問題。

   2、List刪除元素時,為避免陷阱,建議使用迭代器iterator的remove方式。

   3、List刪除元素時,默認(rèn)按索引刪除,而不是對象刪除。

到此這篇關(guān)于Java List的remove()方法踩坑的文章就介紹到這了,更多相關(guān)Java List remove()內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/pelifymeng2/article/details/78085836

延伸 · 閱讀

精彩推薦
  • Java教程淺談Storm在zookeeper上的目錄結(jié)構(gòu)

    淺談Storm在zookeeper上的目錄結(jié)構(gòu)

    這篇文章主要介紹了淺談Storm在zookeeper上的目錄結(jié)構(gòu)的相關(guān)內(nèi)容,涉及storm使用zookeeper的操作以及詳細(xì)結(jié)構(gòu)圖,具有一定參考價值,需要的朋友可以了解下。...

    不懂6272021-01-18
  • Java教程淺談JAVA 線程狀態(tài)中可能存在的一些誤區(qū)

    淺談JAVA 線程狀態(tài)中可能存在的一些誤區(qū)

    這篇文章主要介紹了淺談JAVA 線程狀態(tài)中可能存在的一些誤區(qū),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要...

    空無12162021-09-07
  • Java教程Java 虛擬機(jī)(JVM)之基本概念詳解

    Java 虛擬機(jī)(JVM)之基本概念詳解

    下面小編就為大家?guī)硪黄狫ava 虛擬機(jī)(JVM)之基本概念詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    Java教程網(wǎng)3762020-10-31
  • Java教程詳解SpringBoot健康檢查的實現(xiàn)原理

    詳解SpringBoot健康檢查的實現(xiàn)原理

    這篇文章主要介紹了詳解SpringBoot健康檢查的實現(xiàn)原理,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下...

    筱進(jìn)客6152021-08-23
  • Java教程Java日常練習(xí)題,每天進(jìn)步一點點(10)

    Java日常練習(xí)題,每天進(jìn)步一點點(10)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以...

    牛哄哄的柯南8802021-10-20
  • Java教程Spring Security中的Servlet過濾器體系代碼分析

    Spring Security中的Servlet過濾器體系代碼分析

    這篇文章主要介紹了Spring Security中的Servlet過濾器體系,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需...

    碼農(nóng)小胖哥1862020-07-07
  • Java教程java實現(xiàn)AES可逆加密算法

    java實現(xiàn)AES可逆加密算法

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)AES可逆加密算法,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    風(fēng)過留痕丶7112021-07-24
  • Java教程Spring Boot DevTools使用教程

    Spring Boot DevTools使用教程

    DevTools通過提供自動重啟和LiveReload功能,使您更快、更輕松地開發(fā)Spring Boot應(yīng)用程序。這篇文章主要介紹了Spring Boot DevTools使用教程,需要的朋友可以參考下...

    jdon9602021-06-10
主站蜘蛛池模板: 国产经典一区二区三区蜜芽 | 国产精品香蕉夜间视频免费播放 | 操比视频 | 国产欧美va欧美va香蕉在线观看 | 免费一级夫妻a | 青青成人| 人阁色第四影院在线观看 | 日韩成人影视 | 亚洲男人天堂a | 91精品国产麻豆国产自产在线 | 国内自拍视频在线观看 | 国产在线视频福利 | 亚洲精品卡1卡二卡3卡四卡 | 王小军怎么了最新消息 | 国产精品性视频免费播放 | 日韩成本大片35分钟免费播放 | 白丝爆动漫羞羞动漫网站 | japan孕妇孕交 | 日韩激情视频在线观看 | 欧洲一级 | 亚洲成人一区二区 | 美女跪式抽搐gif动态图 | 色愉拍亚洲偷自拍 | 闺蜜的样子小说安沁在线阅读 | 婷婷日日夜夜 | 成人影院观看 | 狠狠综合久久综合网站 | 日本四虎影视 | 女人麻豆国产香蕉久久精品 | 青青青久热国产精品视频 | bdsm酷刑折磨死美女 | 色综合网亚洲精品久久 | chinese腹肌gay| 国产视频自拍一区 | 全黄h全肉细节修仙玄幻文 全彩调教侵犯h本子全彩妖气he | 日韩欧美一区二区在线观看 | 日韩天堂视频 | 亚洲精品在线免费看 | chinese圣水黄金调教 | 9420高清完整版在线观看国语 | 99热这里只有精品国产在热久久 |