2009-11-20 14 views
4

出於某種原因,我得到一個UnsupportedOpeationException以下代碼。在調試器中檢查它,它看起來像我打電話給remove()的對象是一個列表。Java:爲什麼在列表上調用`remove()`會拋出UnsupportedOperation異常?

// to optimize, remove totalSize. After taking an item from lowest, if lowest is empty, remove it from `lists` 
// lists are sorted to begin with 
public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) { 
    List<T> result = new ArrayList<T>(); 
    HashMap<List<T>, Integer> location = new HashMap<List<T>, Integer>(); 

    int totalSize = 0; // every element in the set 
    for (List<T> l : lists) { 
     location.put(l, 0); 
     totalSize += l.size(); 
    } 

    boolean first; 
    List<T> lowest = lists.iterator().next(); // the list with the lowest item to add 
    int index; 

    while (result.size() < totalSize) { // while we still have something to add 
     first = true; 

     for (List<T> l : lists) { 
      if (! l.isEmpty()) { 
       if (first) { 
        lowest = l; 
       } 
       else if (l.get(location.get(l)).compareTo(lowest.get(location.get(lowest))) <= 0) { 
        lowest = l; 
       } 
      } 
     } 
     index = location.get(lowest); 
     result.add(lowest.get(index)); 
     lowest.remove(index); //problem here 
    } 
    return result; 
} 

例外:

Exception in thread "main" java.lang.UnsupportedOperationException 
    at java.util.AbstractList.remove(Unknown Source) 
    at interview.questions.MergeLists.merge(MergeLists.java:72) 
    at interview.questions.MergeLists.main(MergeLists.java:32) 

這究竟是爲什麼?

+0

我們來看看調用此方法的代碼。 – Drew 2009-11-20 21:41:28

回答

19

您收到的List的底層實現很可能是固定長度的,例如由Arrays#asList創建的。

+0

是的,這就是它實際來源。我能做些什麼來防止它成爲問題? – 2009-11-21 01:47:19

+1

最簡單的方法是將每個輸入列表複製到一個可修改的形式,例如'new LinkedList (l)'。一個更好的方法可能是創建一個新類來充當可循環迭代器,根據迭代的當前元素進行比較,爲每個輸入列表創建一個實例,並將該批次折騰爲「PriorityQueue」。然後,內部循環變得很簡單:從隊列中拉出下一個項目,將其元素附加到輸出中,將其前進,如果它沒有到達列表的末尾,則將其放回隊列中(讓「PriorityQueue」排序您)。 – 2009-11-23 23:23:37

+0

謝謝!我從Hibernate試圖從merge()列表中刪除相同的問題。在單元測試中設置一些測試數據時,我正在使用Arrays#asList。+1,希望我能夠+100! – Derek 2011-04-07 09:35:27

0

難道是你在集合中傳遞的列表是從AbstractList派生的,並沒有實現(支持)remove()方法嗎?

此外,看起來location總是映射到0爲所有映射到位置HashMap中的列表對象?

4

如果你看看API docs for the List interface你會發現它們中的一些是「可選操作」。這意味着一個具體的類可以拋出UnsupportedOperationException異常。

例如,如果列表轉換爲unmodifiable list,它不能允許刪除操作實際刪除某些內容(或列表將被修改)。

因此,對於集<列表< >>部分代碼中的一個或多個列表不允許您從中刪除。

1

對於實現Collection接口的類來說,允許刪除對象是可選的(請參見Collection#remove()這是一個可選操作)。如同在Javadoc中所述,它拋出

UnsupportedOperationException - 如果remove操作不受此集合

你很可能在這種情況下支持(例如,如果您設定包含Arrays.asList爲返回一個列表傑弗裏指出)。

0

Collection接口的remove()方法被明確指定爲可選操作:

remove(Object o) 
      Removes a single instance of the specified element from this collection, if it is present (optional operation). 

列表沒有支持實際上,是因爲它沒有明確的語義。列表並不意味着這種隨機訪問。而不是提供一些可能低效或不準確的默認實現,您會得到例外。

您可以使用for-each循環編寫自己的實用程序方法,以便在重要時執行此操作。

2

如果您打算從List中刪除項目,那麼您應該使用ListIterator,它以安全的方式支持remove(),而不是使用for-each循環遍歷列表在列表中留下空洞或索引指向無處)。

+0

只是好奇,爲什麼downvote?這是一個有效的建議......也許不回答這個問題? – shoover 2009-11-21 22:33:06

相關問題