开发者

Java: Why does calling `remove()` on a List throw UnsupportedOperation exception?

For some reason, I'm getting an UnsupportedOpeationException with the following code. Examining it in the debugger, it looks like the object I'm calling remove() on is a list.

// to optimize, remove totalSize. After taking an item from lowest, if l开发者_运维知识库owest 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;
}

The exception:

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)

Why is this happening?


It's quite possible the underlying implementation of List you received is fixed-length, such as one created by Arrays#asList.


If you look at the API docs for the List interface you will see that a number of them are "optional operations". That means that a concrete class is permitted to throw the UnsupportedOperationException.

If, for example, the List was converted to an unmodifiable list it could not allow the remove operation to actually remove something (or the list would be modified).

So for the Set< List<>> part of the code one or mnre of the lists does not allow you to remove from it.


If you are going to be removing items from a List, then rather than use a for-each loop to iterate through the list, you should be using a ListIterator, which supports remove() in a safe manner (i.e. without leaving holes in the list or an index pointing to nowhere).


It is optional for a class implementing the Collection interface to allow objects to be removed (see Collection#remove() which is an optional operation). As stated in the javadoc, it throws

UnsupportedOperationException - if the remove operation is not supported by this collection

You are likely in that case (e.g. if your set contains a list returned by Arrays.asList as pointed out by Jeffrey).


Could it be that the Lists you pass in the set are derived from AbstractList and do not implement (support) the remove() method?

Also, it seems that location always maps to 0 for all list object that are mapped in the location HashMap?


The remove() method in the Collection interface is explicitly specified as an optional operation:

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

Lists do not have to support in. In fact, there is no clear semantics for it. Lists are not meant for that sort of random-access. Rather than provide some default implementation that may be inefficient or inaccurate, you get the exception.

You can write your own utility method with a for-each loop to do this if it is critical.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜