最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java遍歷集合報(bào)錯(cuò)ConcurrentModificationException的原因分析與解決方法

 更新時(shí)間:2025年11月07日 09:20:45   作者:網(wǎng)羅開發(fā)  
這篇文章主要為大家詳細(xì)介紹了Java遍歷集合時(shí)報(bào)錯(cuò)ConcurrentModificationException的原因分析與對應(yīng)的解決方法,一共有三種方法,大家可以根據(jù)自己的情況進(jìn)行選擇

問題背景:遍歷時(shí)修改集合

在項(xiàng)目中,我們經(jīng)常需要對列表進(jìn)行“邊遍歷邊刪除”的操作,比如清理不符合條件的數(shù)據(jù):

List<String> users = new ArrayList<>();
users.add("Tom");
users.add("Jerry");
users.add("Spike");

// 刪除名字長度小于4的用戶
for (String name : users) {
    if (name.length() < 4) {
        users.remove(name); // 報(bào)錯(cuò)!
    }
}

運(yùn)行結(jié)果如下:

Exception in thread "main" java.util.ConcurrentModificationException

很多初學(xué)者會以為是多線程并發(fā)的問題,其實(shí)不是——這段代碼只有一個(gè)線程。真正的原因在于:我們在使用增強(qiáng) for 循環(huán)(底層是 Iterator)遍歷時(shí)修改了集合結(jié)構(gòu)。

異常原理:fail-fast 機(jī)制

Java 的集合類(如 ArrayListHashMap)在遍歷時(shí)會維護(hù)一個(gè)“結(jié)構(gòu)修改計(jì)數(shù)器(modCount)”。每次調(diào)用 add()remove() 時(shí),modCount 都會遞增。

而在使用 Iterator 遍歷時(shí),迭代器內(nèi)部也保存了一個(gè) expectedModCount,表示它期望的修改次數(shù)。每次 next() 時(shí)都會檢查:

if (modCount != expectedModCount)
    throw new ConcurrentModificationException();

所以,當(dāng)你在遍歷過程中直接操作原集合(而不是通過迭代器),modCount 會變化,而迭代器的 expectedModCount 沒更新,于是觸發(fā)了“fail-fast”保護(hù)機(jī)制。

解決方案 1:使用 Iterator.remove()

最正統(tǒng)、最安全的方式就是用 Iterator 自帶的 remove() 方法。它會在刪除元素的同時(shí)同步更新 expectedModCount,從而避免異常。

List<String> users = new ArrayList<>();
users.add("Tom");
users.add("Jerry");
users.add("Spike");

Iterator<String> iterator = users.iterator();
while (iterator.hasNext()) {
    String name = iterator.next();
    if (name.length() < 4) {
        iterator.remove(); // 正確做法
    }
}

System.out.println(users);

輸出結(jié)果:

[Jerry, Spike]

沒有報(bào)錯(cuò),功能正常。

優(yōu)點(diǎn)

  • 不會觸發(fā) ConcurrentModificationException;
  • 無需復(fù)制集合;
  • 對性能影響小。

缺點(diǎn)

  • 寫法略繁瑣;
  • 只能在單線程環(huán)境中安全使用。

解決方案 2:使用 CopyOnWriteArrayList(線程安全版)

如果你的場景是多線程修改集合,比如在 Web 請求或任務(wù)調(diào)度中共享數(shù)據(jù),可以使用 CopyOnWriteArrayList。

這個(gè)類在寫操作時(shí)會復(fù)制底層數(shù)組,從而保證讀操作不會受寫操作影響。

import java.util.concurrent.CopyOnWriteArrayList;

public class Demo {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> users = new CopyOnWriteArrayList<>();
        users.add("Tom");
        users.add("Jerry");
        users.add("Spike");

        for (String name : users) {
            if (name.length() < 4) {
                users.remove(name); // 不會拋異常
            }
        }

        System.out.println(users);
    }
}

輸出:

[Jerry, Spike]

優(yōu)點(diǎn)

  • 支持多線程安全修改;
  • 不會觸發(fā)并發(fā)修改異常;
  • 讀操作幾乎無鎖,非常快。

缺點(diǎn)

  • 寫操作開銷較大(每次寫都會復(fù)制整個(gè)數(shù)組);
  • 不適合頻繁寫入的場景。

解決方案 3:Stream 流式重建集合(推薦現(xiàn)代寫法)

在 Java 8 之后,其實(shí)最推薦的做法是使用 Stream 進(jìn)行過濾或重建集合。這種寫法既優(yōu)雅又安全,不會破壞原集合。

List<String> users = new ArrayList<>();
users.add("Tom");
users.add("Jerry");
users.add("Spike");

// 使用 Stream 過濾重建集合
users = users.stream()
        .filter(name -> name.length() >= 4)
        .toList(); // 重新生成一個(gè)新列表

System.out.println(users);

輸出:

[Jerry, Spike]

優(yōu)點(diǎn)

  • 不會拋異常;
  • 可讀性好;
  • 更符合函數(shù)式編程風(fēng)格;
  • 支持并行流提升性能。

缺點(diǎn)

會生成新的集合對象(有一定內(nèi)存開銷)。

實(shí)際開發(fā)場景案例

在一個(gè)電商系統(tǒng)中,我們有一個(gè)用戶購物車 List<CartItem>,每次請求結(jié)算時(shí),需要過濾掉失效的商品。

開發(fā)者最開始寫了這樣一段代碼:

for (CartItem item : cartItems) {
    if (!item.isValid()) {
        cartItems.remove(item); // 報(bào) ConcurrentModificationException
    }
}

上線后偶發(fā)異常。

后來改成:

Iterator<CartItem> iterator = cartItems.iterator();
while (iterator.hasNext()) {
    if (!iterator.next().isValid()) {
        iterator.remove(); // 安全刪除
    }
}

或者更現(xiàn)代一點(diǎn):

cartItems = cartItems.stream()
        .filter(CartItem::isValid)
        .toList(); // 優(yōu)雅且安全

這樣既避免了異常,也讓邏輯更清晰。

小結(jié)

方案特點(diǎn)適用場景
Iterator.remove()原地刪除、安全可靠單線程遍歷
CopyOnWriteArrayList線程安全、讀寫分離多線程讀取多、寫入少
Stream 過濾重建優(yōu)雅簡潔、不可變式編程推薦現(xiàn)代開發(fā)風(fēng)格

結(jié)語

ConcurrentModificationException 本質(zhì)上是 Java 集合為我們提供的一種保護(hù)機(jī)制,防止在遍歷過程中意外修改數(shù)據(jù)導(dǎo)致不可預(yù)期結(jié)果。只要理解了它的底層原理——“fail-fast 校驗(yàn) modCount”,你就能輕松避開這類問題。

簡單記一句話:

遍歷時(shí)不要直接改集合,要么用迭代器,要么重建集合。

到此這篇關(guān)于Java遍歷集合報(bào)錯(cuò)ConcurrentModificationException的原因分析與解決方法的文章就介紹到這了,更多相關(guān)Java ConcurrentModificationException異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java notify和notifyAll的對比

    java notify和notifyAll的對比

    這篇文章主要介紹了 java notify和notifyAll的對比的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • java.lang.Void 與 void的比較及使用方法介紹

    java.lang.Void 與 void的比較及使用方法介紹

    這篇文章主要介紹了java.lang.Void 與 void的比較及使用方法介紹,小編覺得挺不錯(cuò)的,這里給大家分享一下,需要的朋友可以參考。
    2017-10-10
  • 解決SpringBoot跨域的三種方式

    解決SpringBoot跨域的三種方式

    前后端分離是目前的趨勢,解決跨域問題也是老生常談的話題了,我們了解一下什么是域和跨域。域:協(xié)議 + 域名 + 端口;三者完全相同則為同域,反之有其一不同均為不同域。跨域請求:當(dāng)前【發(fā)起請求】的域和【請求指向】的域?qū)儆诓煌驎r(shí),該次請求稱之為跨域請求
    2021-06-06
  • linux環(huán)境下java程序打包成簡單的hello world輸出jar包示例

    linux環(huán)境下java程序打包成簡單的hello world輸出jar包示例

    這篇文章主要介紹了linux環(huán)境下java程序打包成簡單的hello world輸出jar包,結(jié)合簡單hello world輸出程序示例分析了Linux環(huán)境下的java可執(zhí)行jar包文件的生成相關(guān)操作技巧,需要的朋友可以參考下
    2019-11-11
  • Spring Boot中如何使用斷路器詳解

    Spring Boot中如何使用斷路器詳解

    這篇文章主要給大家介紹了關(guān)于Spring Boot中如何使用斷路器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • java中Supplier、Function、BiFunction的區(qū)別及說明

    java中Supplier、Function、BiFunction的區(qū)別及說明

    Supplier、Function、BiFunction是Java函數(shù)式編程中常用的三個(gè)接口,它們分別用于無參數(shù)返回值、單參數(shù)返回值和雙參數(shù)返回值的抽象函數(shù)定義
    2026-04-04
  • 詳細(xì)了解MVC+proxy

    詳細(xì)了解MVC+proxy

    Java有兩種代理方式,一種是靜態(tài)代理,另一種是動態(tài)代理。對于靜態(tài)代理,其實(shí)就是通過依賴注入,對對象進(jìn)行封裝,不讓外部知道實(shí)現(xiàn)的細(xì)節(jié)。很多 API 就是通過這種形式來封裝的
    2021-07-07
  • Java實(shí)現(xiàn)微信登錄并獲取用戶信息功能(開發(fā)流程)

    Java實(shí)現(xiàn)微信登錄并獲取用戶信息功能(開發(fā)流程)

    這篇文章主要介紹了Java實(shí)現(xiàn)微信登錄并獲取用戶信息功能(開發(fā)流程),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • JWT + 攔截器實(shí)現(xiàn)無狀態(tài)登錄系統(tǒng)

    JWT + 攔截器實(shí)現(xiàn)無狀態(tài)登錄系統(tǒng)

    JWT(JSON Web Token)提供了一種無狀態(tài)的解決方案:用戶登錄后,服務(wù)器返回一個(gè) Token,后續(xù)請求攜帶該 Token 即可完成身份驗(yàn)證,無需服務(wù)器存儲會話信息,本文將結(jié)合 Spring Boot 攔截器,手把手實(shí)現(xiàn)一個(gè)完整的JWT無狀態(tài)登錄系統(tǒng),感興趣的朋友一起看看吧

    2025-08-08
  • JAVA十大排序算法之計(jì)數(shù)排序詳解

    JAVA十大排序算法之計(jì)數(shù)排序詳解

    這篇文章主要介紹了java中的計(jì)數(shù)排序,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08

最新評論

咸阳市| 北流市| 常宁市| 维西| 漯河市| 葫芦岛市| 武山县| 冕宁县| 黄陵县| 会宁县| 沧州市| 安达市| 洪湖市| 揭东县| 项城市| 治多县| 渝中区| 黎城县| 英吉沙县| 绥化市| 通辽市| 府谷县| 岚皋县| 麻城市| 洮南市| 古浪县| 东乡县| 靖远县| 德兴市| 噶尔县| 洪雅县| 图片| 锦屏县| 沈阳市| 新邵县| 定结县| 大埔县| 开封县| 南京市| 南靖县| 郸城县|