java.lang.UnsupportedOperationException解決方法

在最近做的一個項目中對List進行操作時報錯java.lang.UnsupportedOperationException,後來發現操作的List是由數組轉換而成的,通過看源碼發現問題,並寫測試程序如下。 

代碼塊:

public class Unsupported {

    static void test(String msg, List<String> list) {
        System.out.println("---- " + msg + "----");
        Collection<String> c = list;
        Collection<String> subList = list.subList(1, 8);
        //  複製子List
        Collection<String> c2 = new ArrayList<>(subList);
        try {
            c.retainAll(c2);
        } catch (Exception e) {
            System.out.println("retainAll()方法的異常: " + e);
        }
        try {
            c.removeAll(c2);
        } catch (Exception e) {
            System.out.println("removeAll()方法的異常: " + e);
        }
        try {
            c.clear();
        } catch (Exception e) {
            System.out.println("clear()方法的異常: " + e);
        }
        try {
            c.add("X");
        } catch (Exception e) {
            System.out.println("add()方法的異常: " + e);
        }
        try {
            c.addAll(c2);
        } catch (Exception e) {
            System.out.println("addAll()方法的異常: " + e);
        }
        try {
            c.remove("C");
        } catch (Exception e) {
            System.out.println("remove()方法的異常: " + e);
        }
        // list.set() 方法修改值,但是沒有改變數據結構的大小
        try {
            list.set(0, "X");
        } catch (Exception e) {
            System.out.println("list.set()方法的異常: " + e);
        }
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("A B C D E F G H I J K L".split(" "));
        test("複製操作: ", new ArrayList<String>(list));
        System.out.println("**********一條華麗的分割線**********");
        test("Arrays.asList的操作: ", list);
        test("unmodifiableList()的操作: ", Collections.unmodifiableList(list));
    }
}

執行結果:

---- 複製操作: ----
**********一條華麗的分割線**********
---- Arrays.asList的操作: ----
retainAll()方法的異常: java.lang.UnsupportedOperationException
removeAll()方法的異常: java.lang.UnsupportedOperationException
clear()方法的異常: java.lang.UnsupportedOperationException
add()方法的異常: java.lang.UnsupportedOperationException
addAll()方法的異常: java.lang.UnsupportedOperationException
remove()方法的異常: java.lang.UnsupportedOperationException
---- unmodifiableList()的操作: ----
retainAll()方法的異常: java.lang.UnsupportedOperationException
removeAll()方法的異常: java.lang.UnsupportedOperationException
clear()方法的異常: java.lang.UnsupportedOperationException
add()方法的異常: java.lang.UnsupportedOperationException
addAll()方法的異常: java.lang.UnsupportedOperationException
remove()方法的異常: java.lang.UnsupportedOperationException
list.set()方法的異常: java.lang.UnsupportedOperationException

產生的原因

調用Arrays.asList()生產的List的add、remove方法時報異常,這是由Arrays.asList() 返回的是Arrays的內部類ArrayList, 而不是java.util.ArrayList。Arrays的內部類ArrayList和java.util.ArrayList都是繼承AbstractList,remove、add等方法AbstractList中是默認throw UnsupportedOperationException而且不作任何操作。java.util.ArrayList重新了這些方法而Arrays的內部類ArrayList沒有重新,所以會拋出異常。解決方法如下:

通過再新建一個ArrayList,讓這些方法重新實現AbstractList的方法,如下圖:

以下內容摘自Java編程思想(第四版):

因爲Arrays.asList()會生成一個List,它基於一個固定大小的數組,而這個數組僅支持那些不會改變數組大小的操作。任何會引起對底層數據結構的尺寸進行修改的方法都會產生一個UnsupportedOperation Exception異常,以表示對未獲支持操作的調用(一個編程錯誤)。

注意,應該把Arrays.asList()的結果作爲構造器的參數傳遞給任何Collection(或者使用addAll()方法,或者 Collections.addAll()靜態方法),這樣可以生成允許使用所有的方法的普通容器----這在 main()方法中的第一個對test的調用中得到了展示,這樣的調用會產生新的尺寸可調的底層數據結構。 Collections類中的“不可修改”的方法將容器包裝到了一個代理中,只要你執行任何試圖修改容器的操作,這個代理都會產生UnsupportedOperationException異常。使用這些方法的目標就是產生“常量”容器對象。“不可修改”的Collections方法的完整列表將在稍後介紹。

test方法中的最後一個try語句塊將檢查作爲List的一部分的set()方法。這很有趣,因爲你可以看到“未獲支持的操作”這一技術的粒度來的是多麼方便----所產生的“接口”可以在Arrays. asListCollections()返回的對象和Collections.unmodifiableList()返回的對象之間,在一個方法的粒度上產生變化。 Arrays.asList()返回固定尺寸的List,而 Collections. unmodifiableListO產生不可修改的列表。正如從輸出中所看到的,修改 Arrays. asList()返回的List中的元素是可以的,因爲這沒有違反該List“尺寸固定”這一特性但是很明顯,unmodifiableList()的結果在任何情況下都應該不是可修改的。如果使用的是接口,那麼還需要兩個附加的接口,一個具有可以工作的set()方法,另外一個沒有,因爲附加的接口對於 Collection的各種不可修改的子類型來說是必需的。

 

【參考資料】

1、Java編程思想(第四版)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章