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

Java中的forEach循環(huán)詳細(xì)解讀

 更新時間:2023年12月19日 09:11:10   作者:初念初戀  
這篇文章主要介紹了Java中的forEach循環(huán)詳細(xì)解讀,不要再foreach循環(huán)里面進(jìn)行元素的add和remove,如果你非要進(jìn)行remove元素,那么請使用Iterator方式,如果存在并發(fā),那么你一定要選擇加鎖,需要的朋友可以參考下

前言

相信大家肯定都看過阿里巴巴開發(fā)手冊,而在阿里巴巴開發(fā)手冊中明確的指出,不要再foreach循環(huán)里面進(jìn)行元素的add和remove,如果你非要進(jìn)行remove元素,那么請使用Iterator方式,如果存在并發(fā),那么你一定要選擇加鎖。

foreach

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("11");
        list.add("22");
        list.add("33");
        list.add("44");
        for (String s : list) {
            if ("22".equalsIgnoreCase(s)) {
                list.remove(s);
            }
        }
        System.out.println(JSONObject.toJSONString(list));
    }

輸出結(jié)果:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at org.example.list.Test01.main(Test01.java:22)
Process finished with exit code 1

分析異常:

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

比較兩個值 modCount 和expectedModCount,那么這兩個變量是什么呢?

其中modCount表示集合的修改次數(shù),這其中包括了調(diào)用集合本身的add方法等修改方法時進(jìn)行的修改和調(diào)用集合迭代器的修改方法進(jìn)行的修改。而expectedModCount則是表示迭代器對集合進(jìn)行修改的次數(shù)。

先來看看反編譯之后的代碼,如下:

    public static void main(String[] args) {
        List<String> list = new ArrayList();
        list.add("11");
        list.add("22");
        list.add("33");
        list.add("44");
        Iterator var2 = list.iterator();
        while(var2.hasNext()) {
            String s = (String)var2.next();
            if ("22".equalsIgnoreCase(s)) {
                list.remove(s);
            }
        }
        System.out.println(JSONObject.toJSONString(list));
    }

看里面使用的也是迭代器,也就是說,其實(shí) foreach 每次循環(huán)都調(diào)用了一次iterator的next()方法, foreach方式中調(diào)用的remove方法,是ArrayList內(nèi)部的remove方法,會更新modCount屬性

我們可以看看ArrayList類中的remove方法

    public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        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
        return oldValue;
    }

看到此方法中,有一個modCount++的操作,也就是說,modCount會一直更新變化。

我們第一次迭代的時候 11 != 22 ,直接迭代第二次,這時候就相等了,執(zhí)行remove()方法,這時候就是modCount++,再次調(diào)用next()的時候,modCount = expectedModCount 這個就不成立了,所以異常信息出現(xiàn)了,其實(shí)也可以理解為在 hasNext() 里面,cursor != size 而這時候就會出現(xiàn)錯誤了。

也就是說 remove方法它只修改了modCount,并沒有對expectedModCount做任何操作。

迭代器

為什么阿里巴巴的規(guī)范手冊會這樣子定義?

img

它為什么推薦我們使用 Iterator呢?

直接使用迭代器會修改expectedModCount,而我們使用foreach的時候,remove方法它只修改了modCount,并沒有對expectedModCount做任何操作,而Iterator就不會這個樣子。

   public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("11");
        list.add("22");
        list.add("33");
        list.add("44");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String item = iterator.next();
            if("22".equals(item)){
                iterator.remove();
            }
        }
        System.out.println(JSONObject.toJSONString(list));
    }

輸出結(jié)果:

["11","33","44"]
Process finished with exit code 0

可以看出結(jié)果是正確的,下面我們來分析一下:

先來看看反編譯之后的代碼:

    public static void main(String[] args) {
        List<String> list = new ArrayList();
        list.add("11");
        list.add("22");
        list.add("33");
        list.add("44");
        Iterator iterator = list.iterator();
        while(iterator.hasNext()) {
            String item = (String)iterator.next();
            if ("22".equals(item)) {
                iterator.remove();
            }
        }
        System.out.println(JSONObject.toJSONString(list));
    }

主要觀察remove()方法的實(shí)現(xiàn),那么需要先看 ArrayList.class:

    public Iterator<E> iterator() {
        return new Itr();
    }
    /**
     * An optimized version of AbstractList.Itr
     */
    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() {}
        public boolean hasNext() {
            return cursor != size;
        }
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();     //第一步
            try {
                ArrayList.this.remove(lastRet);   //第二步:調(diào)用list的remove方法
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount; 		//第三步:modCount是remove方法去維護(hù)更新,
                                                    //由于第一步中校驗 modCount 和 expectedModCount 是否相當(dāng)?shù)?
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
  1. 調(diào)用 checkForComodification()方法,作用:判斷modCount 和 expectedModCount 是否相當(dāng);
  2. foreach 方式中調(diào)用的remove方法,是ArrayList內(nèi)部的remove方法,會更新modCount屬性;
  3. 將更新后的modCount重新賦值給expectedModCount變量。

Java8的新特性

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("11");
        list.add("22");
        list.add("33");
        list.add("44");
        list.removeIf("22"::equals);
        System.out.println(JSONObject.toJSONString(list));
    }

總結(jié)

for-each循環(huán)不僅適用于遍歷集合和數(shù)組,而且能讓你遍歷任何實(shí)現(xiàn)Iterator接口的對象;最最關(guān)鍵的是它還沒有性能損失。

而對數(shù)組或集合進(jìn)行修改(添加刪除操作),就要用迭代器循環(huán)。所以循環(huán)遍歷所有數(shù)據(jù)的時候,能用它的時候還是選擇它吧。

到此這篇關(guān)于Java中的forEach循環(huán)詳細(xì)解讀的文章就介紹到這了,更多相關(guān)forEach循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決idea每次新建項目都需要重新指定maven目錄

    解決idea每次新建項目都需要重新指定maven目錄

    這篇文章主要介紹了解決idea每次新建項目都需要配置maven,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringBoot底層注解詳解

    SpringBoot底層注解詳解

    這篇文章主要介紹了SpringBoot底層注解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-05-05
  • 關(guān)于泛型擦除問題的解決--Mybatis查詢類型轉(zhuǎn)換

    關(guān)于泛型擦除問題的解決--Mybatis查詢類型轉(zhuǎn)換

    這篇文章主要介紹了關(guān)于泛型擦除問題的解決--Mybatis查詢類型轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Springboot3集成Knife4j的步驟以及使用(最完整版)

    Springboot3集成Knife4j的步驟以及使用(最完整版)

    這篇文章主要介紹了Springboot3集成Knife4j的步驟以及使用的相關(guān)資料,Knife4j是一種增強(qiáng)Swagger的工具,支持黑色主題和更多配置選項,它與swagger-bootstrap-ui相比,提供了更現(xiàn)代的外觀和更多的功能,需要的朋友可以參考下
    2024-11-11
  • java實(shí)現(xiàn)百度坐標(biāo)的摩卡托坐標(biāo)與火星坐標(biāo)轉(zhuǎn)換的示例

    java實(shí)現(xiàn)百度坐標(biāo)的摩卡托坐標(biāo)與火星坐標(biāo)轉(zhuǎn)換的示例

    這篇文章主要介紹了java實(shí)現(xiàn)百度坐標(biāo)的摩卡托坐標(biāo)與火星坐標(biāo)轉(zhuǎn)換的示例,需要的朋友可以參考下
    2014-03-03
  • springboot如何根據(jù)配置屏蔽接口返回字段

    springboot如何根據(jù)配置屏蔽接口返回字段

    這篇文章主要介紹了springboot如何根據(jù)配置屏蔽接口返回字段問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java中的數(shù)組使用詳解及練習(xí)

    Java中的數(shù)組使用詳解及練習(xí)

    數(shù)組是Java程序中最常見的一種數(shù)據(jù)結(jié)構(gòu),它能夠?qū)⑾嗤愋偷臄?shù)據(jù)用一個標(biāo)識符封裝到一起,構(gòu)成一個對象序列或基本數(shù)據(jù)類型,這篇文章主要給大家介紹了關(guān)于Java中數(shù)組使用詳解及練習(xí)的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • Java中split根據(jù)"."分割字符串問題舉例

    Java中split根據(jù)"."分割字符串問題舉例

    split表達(dá)式其實(shí)就是一個正則表達(dá)式,* | . ^ 等符號在正則表達(dá)式中屬于一種有特殊含義的字符,下面這篇文章主要給大家介紹了關(guān)于Java中split根據(jù)“.“分割字符串問題的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • Java實(shí)現(xiàn)根據(jù)模板自動生成新的PPT

    Java實(shí)現(xiàn)根據(jù)模板自動生成新的PPT

    這篇文章主要介紹了如何利用Java代碼自動生成PPT,具體就是查詢數(shù)據(jù)庫數(shù)據(jù),然后根據(jù)模板文件(PPT),將數(shù)據(jù)庫數(shù)據(jù)與模板文件(PPT),進(jìn)行組合一下,生成新的PPT文件。感興趣的可以了解一下
    2022-02-02
  • SpringBoot集成JWT的工具類與攔截器實(shí)現(xiàn)方式

    SpringBoot集成JWT的工具類與攔截器實(shí)現(xiàn)方式

    這篇文章主要介紹了SpringBoot集成JWT的工具類與攔截器實(shí)現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評論

东丰县| 通海县| 内丘县| 梧州市| 怀宁县| 梅河口市| 启东市| 拉萨市| 岢岚县| 清水河县| 华容县| 郓城县| 札达县| 开远市| 城口县| 沁阳市| 岗巴县| 桐梓县| 屏东市| 乐至县| 永平县| 金川县| 濮阳市| 达拉特旗| 泰安市| 桓台县| 青浦区| 格尔木市| 盐边县| 广东省| 呼图壁县| 揭阳市| 海安县| 元阳县| 宕昌县| 镇平县| 甘孜县| 温宿县| 鄄城县| 晴隆县| 清水河县|