亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中for循環(huán)內(nèi)修改集合的常見陷阱與最佳實踐

 更新時間:2025年06月16日 08:24:16   作者:碼農(nóng)阿豪@新空間  
在Java編程中,for循環(huán)是遍歷集合(如List、Set)的常用方式,本文主要介紹了Java在for循環(huán)內(nèi)修改集合的常見陷阱與最佳實踐,希望對大家有所幫助

1. 引言

在Java編程中,for循環(huán)是遍歷集合(如List、Set)的常用方式。然而,許多開發(fā)者在循環(huán)內(nèi)部直接對集合進行增刪改操作時,往往會遇到ConcurrentModificationException異常。例如:

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
for (Integer num : numbers) {
    if (num % 2 == 0) {
        numbers.remove(num); // 拋出ConcurrentModificationException
    }
}

本文將深入探討Java集合在循環(huán)中修改的問題,分析fail-fast機制,并提供線程安全的修改方案。

2. 問題現(xiàn)象:為什么在for循環(huán)中修改集合會出錯?

2.1 典型錯誤示例

(1)增強for循環(huán)刪除元素

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String s : list) {
    if (s.equals("B")) {
        list.remove(s); // 拋出ConcurrentModificationException
    }
}

異常原因:Java的for-each循環(huán)使用Iterator,直接修改集合會導(dǎo)致迭代器狀態(tài)不一致。

(2)普通for循環(huán)刪除元素(可能出錯)

List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
for (int i = 0; i < nums.size(); i++) {
    if (nums.get(i) % 2 == 0) {
        nums.remove(i); // 可能導(dǎo)致元素跳過
    }
}
// 結(jié)果可能是 [1, 3, 4] 而非預(yù)期的 [1, 3]

問題:刪除元素后列表大小變化,但循環(huán)索引繼續(xù)遞增,導(dǎo)致某些元素被跳過。

3. 深入分析:Java集合的fail-fast機制

3.1 什么是fail-fast?

Java的ArrayList、HashSet等非線程安全集合采用fail-fast機制:

當(dāng)?shù)鳈z測到集合被并發(fā)修改(即非通過迭代器自身的方法修改),立即拋出ConcurrentModificationException。

目的是快速失敗,避免潛在的數(shù)據(jù)不一致問題。

3.2 源碼分析

以ArrayList為例,其Iterator實現(xiàn)會檢查modCount(修改計數(shù)器):

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

modCount:集合結(jié)構(gòu)修改次數(shù)(如add、remove)。

expectedModCount:迭代器預(yù)期的修改次數(shù)。

直接調(diào)用list.remove()會修改modCount,導(dǎo)致與expectedModCount不一致。

4. 解決方案:安全修改集合的幾種方法

4.1 方法1:使用Iterator的remove()方法(推薦)

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
Iterator<Integer> it = numbers.iterator();
while (it.hasNext()) {
    Integer num = it.next();
    if (num % 2 == 0) {
        it.remove(); // 安全刪除
    }
}
System.out.println(numbers); // [1, 3]

優(yōu)點:

迭代器自身維護modCount,不會觸發(fā)異常。

適用于單線程環(huán)境。

4.2 方法2:使用Java 8+的removeIf()

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
numbers.removeIf(num -> num % 2 == 0);
System.out.println(numbers); // [1, 3]

優(yōu)點:

代碼簡潔,內(nèi)部使用Iterator實現(xiàn)。

性能較好。

4.3 方法3:使用CopyOnWriteArrayList(線程安全)

List<Integer> numbers = new CopyOnWriteArrayList<>(Arrays.asList(1, 2, 3, 4));
for (Integer num : numbers) {
    if (num % 2 == 0) {
        numbers.remove(num); // 安全但性能較低
    }
}
System.out.println(numbers); // [1, 3]

適用場景:

多線程環(huán)境。

缺點:每次修改會復(fù)制整個數(shù)組,性能較差。

4.4 方法4:普通for循環(huán)反向遍歷

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
for (int i = numbers.size() - 1; i >= 0; i--) {
    if (numbers.get(i) % 2 == 0) {
        numbers.remove(i); // 避免索引錯位
    }
}
System.out.println(numbers); // [1, 3]

優(yōu)點:

無需額外迭代器或副本。

適用于簡單刪除邏輯。

4.5 方法5:記錄待刪除元素,最后批量刪除

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
List<Integer> toRemove = new ArrayList<>();
for (Integer num : numbers) {
    if (num % 2 == 0) {
        toRemove.add(num);
    }
}
numbers.removeAll(toRemove);
System.out.println(numbers); // [1, 3]

適用場景:

需要復(fù)雜條件判斷時。

缺點:需要額外空間存儲待刪除元素。

5. 性能對比:不同方法的效率分析

方法時間復(fù)雜度空間復(fù)雜度線程安全適用場景
Iterator.remove()O(n)O(1)單線程推薦
removeIf()O(n)O(1)Java 8+簡潔寫法
CopyOnWriteArrayListO(n²)O(n)多線程環(huán)境
反向遍歷O(n)O(1)簡單刪除邏輯
記錄后批量刪除O(n)O(n)復(fù)雜刪除條件

結(jié)論:

單線程下優(yōu)先選擇Iterator.remove()或removeIf()。

多線程環(huán)境使用CopyOnWriteArrayList或加鎖。

大數(shù)據(jù)量避免CopyOnWriteArrayList,選擇Iterator或反向遍歷。

6. 最佳實踐總結(jié)

禁止在增強for循環(huán)中直接修改集合,改用Iterator.remove()。

Java 8+推薦removeIf(),代碼更簡潔。

多線程環(huán)境使用并發(fā)集合(如CopyOnWriteArrayList)或同步塊。

大規(guī)模數(shù)據(jù)刪除優(yōu)先選擇Iterator或反向遍歷。

復(fù)雜條件刪除可先記錄元素,再批量刪除。

7. 結(jié)論

在Java中,直接于for循環(huán)內(nèi)修改集合會觸發(fā)ConcurrentModificationException,根源在于fail-fast機制。
安全修改集合的最佳實踐包括:

  • 單線程:Iterator.remove()或removeIf()
  • 多線程:CopyOnWriteArrayList或同步控制

掌握這些方法后,可以避免常見陷阱,寫出更健壯的Java代碼。 

到此這篇關(guān)于Java中for循環(huán)內(nèi)修改集合的常見陷阱與最佳實踐的文章就介紹到這了,更多相關(guān)Java for循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 從0開始學(xué)習(xí)大數(shù)據(jù)之java spark編程入門與項目實踐

    從0開始學(xué)習(xí)大數(shù)據(jù)之java spark編程入門與項目實踐

    這篇文章主要介紹了從0開始學(xué)習(xí)大數(shù)據(jù)之java spark編程入門與項目實踐,結(jié)合具體入門項目分析了大數(shù)據(jù)java spark編程項目建立、調(diào)試、輸出等相關(guān)步驟及操作技巧,需要的朋友可以參考下
    2019-11-11
  • Java并發(fā)編程中的ReentrantLock類詳解

    Java并發(fā)編程中的ReentrantLock類詳解

    這篇文章主要介紹了Java并發(fā)編程中的ReentrantLock類詳解,ReentrantLock是juc.locks包中的一個獨占式可重入鎖,相比synchronized,它可以創(chuàng)建多個條件等待隊列,還支持公平/非公平鎖、可中斷、超時、輪詢等特性,需要的朋友可以參考下
    2023-12-12
  • MyBatis常用的jdbcType數(shù)據(jù)類型

    MyBatis常用的jdbcType數(shù)據(jù)類型

    這篇文章主要介紹了MyBatis常用的jdbcType數(shù)據(jù)類型的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 淺談java中的一維數(shù)組、二維數(shù)組、三維數(shù)組、多維數(shù)組

    淺談java中的一維數(shù)組、二維數(shù)組、三維數(shù)組、多維數(shù)組

    下面小編就為大家?guī)硪黄獪\談java中的一維數(shù)組、二維數(shù)組、三維數(shù)組、多維數(shù)組。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • SpringCloud升級2020.0.x版之OpenFeign簡介與使用實現(xiàn)思路

    SpringCloud升級2020.0.x版之OpenFeign簡介與使用實現(xiàn)思路

    在微服務(wù)系統(tǒng)中,我們經(jīng)常會進行 RPC 調(diào)用。在 Spring Cloud 體系中,RPC 調(diào)用一般就是 HTTP 協(xié)議的調(diào)用。對于每次調(diào)用,都要經(jīng)過一系列詳細(xì)步驟,接下來通過本文給大家介紹SpringCloud OpenFeign簡介與使用,感興趣的朋友一起看看吧
    2021-10-10
  • Java Swing中的JButton、JComboBox、JList和JColorChooser組件使用案例

    Java Swing中的JButton、JComboBox、JList和JColorChooser組件使用案例

    這篇文章主要介紹了Java Swing中的按鈕(JButton)、組合框(JComboBox)、下拉列表(JList)和顏色選擇器(JColorChooser)組件使用案例,需要的朋友可以參考下
    2014-10-10
  • Springboot整合SpringSecurity的完整案例詳解

    Springboot整合SpringSecurity的完整案例詳解

    Spring Security是基于Spring生態(tài)圈的,用于提供安全訪問控制解決方案的框架,Spring Security登錄認(rèn)證主要涉及兩個重要的接口 UserDetailService和UserDetails接口,本文對Springboot整合SpringSecurity過程給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2024-01-01
  • 關(guān)于post請求內(nèi)容無法重復(fù)獲取的解決方法

    關(guān)于post請求內(nèi)容無法重復(fù)獲取的解決方法

    這篇文章主要介紹了關(guān)于post請求內(nèi)容無法重復(fù)獲取的解決方法,文中通過代碼示例給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-03-03
  • 使用Zookeeper實現(xiàn)分布式鎖

    使用Zookeeper實現(xiàn)分布式鎖

    這篇文章主要介紹了使用Zookeeper實現(xiàn)分布式鎖,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • SpringBoot多文件分布式上傳功能實現(xiàn)

    SpringBoot多文件分布式上傳功能實現(xiàn)

    本文詳細(xì)介紹了如何在SpringBoot中實現(xiàn)多文件分布式上傳,并用代碼給出了相應(yīng)的實現(xiàn)思路和實現(xiàn)步驟,感興趣的朋友跟隨小編一起看看吧
    2023-06-06

最新評論