天天看點

Java集合周遊引發的"血案"

一、List集合疊代方式周遊一

   <1>、可能出現的問題一:出現并發修改異常(ConcurrentModificationException)

import java.util.ArrayList;  

import java.util.Iterator;  

import java.util.List;  

public class Test  {  

    private static List<String> list = new ArrayList<String>();  

    public static void init(int num)   {  

        for (int i = 0; i < num; i++)   {  

            list.add(i + "");  

        }  

    }  

    @SuppressWarnings("all")  

    public static void main(String[] args)   {  

        int num = 5;  

        init(num);  

        for (Iterator iterator = list.iterator(); iterator.hasNext();)  {  

            String string = (String) iterator.next();  

            if (string.equals(num - 1 + ""))   {  

                System.out.println("執行remove操作");  

                list.remove(string);  

            }   else   {  

                System.out.println(string);  

            }  

       }  

}  

  上述運作結果如下:

Java集合周遊引發的"血案"

 上述示例出現ConcurrentModificationException異常的原因在于不能對list集合同時進行讀寫操作。

   <2>、可能出現的情況二:下标/遊标錯位

    public static void init(int num)  {  

        for (int i = 0; i < num; i++)  {  

        for (Iterator iterator = list.iterator(); iterator.hasNext();)   {  

            if (string.equals(num - 2 + ""))  {  

            }  else  {  

Java集合周遊引發的"血案"

上述結果顯然是有問題的,我們認為的正确結果應該是:

1

2

執行remove操作

4

那為什麼沒有列印4呢?原因:當if條件成立時,也就是string等于3時,執行移除操作,下标為3的元素移除後,那下标為4的元素前移一位,就剛好滿足跳出循環的條件,因為遊标在3的位置,前移後下标為4的位置就沒有元素了,這時結束循環,直接跳過了4這個元素。

二、List集合疊代方式周遊二

  <1>、可能出現的問題一:出現并發修改異常(ConcurrentModificationException)

        for (String string : list)   {  

            if (string.equals(num - 1 + ""))  {  

            }   else  {  

上述執行結果如下:

Java集合周遊引發的"血案"

    <2>、可能出現的情況二:下标/遊标錯位

            if (string.equals(num - 2 + ""))   {  

            }  else   {  

        }   

 上述運作結果如下:

Java集合周遊引發的"血案"

很容易看出,上面兩個示例跟第一種疊代方式的結果是一樣的,那可能就會有人說,這個兩個不是增強for循環嘛,怎麼成了疊代了?其實增強for循環底層實作就是走疊代的方式。是以結果一樣沒什麼奇怪的,它們出錯的原理也是一樣的,我這裡就不多說了。

三、List非疊代方式周遊

public class Test {  

                   list.add(i + "");  

    public static void main(String[] args)  {  

        for (int i = 0; i < list.size(); i++)   {  

            String string = list.get(i);  

 上述執行結果如下:

Java集合周遊引發的"血案"

 從結果可以看出跟方式一和方式二的第二種情況是一樣的,還是會造成下标錯位,原理一樣,我這裡就不說了,但是不會出現并發修改異常。

四、解決方案

講了怎麼多了,該講講怎麼解決該問題了,解決該問題的方式有多種,我下面介紹兩種解決方案。

<1>、使用并發庫(java.util.concurrent)下的CopyOnWriteArrayList類可以解決該問題,但是性能開銷很大。

import java.util.concurrent.CopyOnWriteArrayList;  

public class Test  {    

    private static List<String> list = new CopyOnWriteArrayList<String>();  

    public static void main(String[] args)    {  

        init(num);          

        for (String string : list)  {  

            if (string.equals(num - 1 + ""))  

            // if (string.equals(num - 2 + ""))  

            {  

            } else  {  

上面代碼可以自己複制到你的編譯器中執行檢視結果,我這裡就不把執行結果貼出來了。

   <2>、先使用一個臨時的List集合來存放需要移除的元素,最後使用removeAll方法來移除所有。

public class TestDemo  {  

    public static void init(int num) {  

        List<String> delList = new ArrayList<String>();  

             if (string.equals(num - 1 + ""))   {  

                delList.add(string);  

        } 

        list.removeAll(delList);  

 上面代碼可以自己複制到你的編譯器中執行檢視結果,我這裡就不把執行結果貼出來了。

   最後講一點Set集合出現的錯誤情況以及解決方案是類似的,要懂得舉一反三,Set集合對應CopyOnWriteArraySet類。

本文轉自 www19 51CTO部落格,原文連結:http://blog.51cto.com/doujh/1940240,如需轉載請自行聯系原作者