在对ArrayList进行操作时,使用AbstractList.remove()会导致UnsupportedOperationException异常。

54

ArrayList的列表迭代器确实实现了remove方法,但是我会抛出以下异常:

UnsupportedOperationException at java.util.AbstractList.remove(AbstractList.java:144)

通过这段代码:

protected void removeZeroLengthStringsFrom(List<String> stringList)
{
    ListIterator<String> iter = stringList.listIterator();
    String s;
    while (iter.hasNext())
    {
        s = iter.next();
        if (s.length() == 0)
        {
            iter.remove();
        }
    }
}

我在这里漏掉了什么?我已经验证了我传递的List<String>确实是ArrayList<String>

谢谢!


有多个线程在同一个 List<String> 上操作吗? - matt b
1
我建议您验证stringList的运行时类型是否真的是java.util.ArrayList类型。我怀疑您可能有一个来自某个不同包的VectorStackArrayList,它没有覆盖remove(int)方法。 - Jim Garrison
你是如何验证的?在 removeZeroLengthStringsFrom() 中,你是否直接检查了 stringList.getClass() 等内容? - QuantumMechanic
2个回答

151

我认为您可能正在使用Arrays工具获取传递到该方法中的List。该对象确实是ArrayList类型,但它是java.util.Arrays.ArrayList而不是java.util.ArrayList

java.util.Arrays.ArrayList版本是不可变的,它的remove()方法没有被覆盖。因此,它会转而使用AbstractListremove()实现,后者会抛出一个UnsupportedOperationException异常。


1
那有什么解决方案?!! - Exceptional
38
解决方案类似于这样:new ArrayList<>(Arrays.asList("a", "b", "c"))。 - Kong
1
有两种可能的解决方案。第一种,正如Kong所暗示的那样,是复制不可变的ArrayList并将其传递进去。第二种,也是更好的解决方案(在我看来),是重写remove...以返回一个List,并在方法中构造一个新的可变List,将其返回给调用者。这种解决方案并不总是可行的(例如,如果您已经连接到一个无法修改的框架),但O(n)(迭代)比O(2n)(复制然后迭代)略好。 - Mike M

2

我认为你所接收到的不是ArrayList,因为ArrayList的迭代器的remove方法不会抛出该异常。

我猜测你所接收到的是一个用户派生的ArrayList类,它的迭代器在remove时会抛出该异常。

public void remove() {
    if (lastRet == -1)
    throw new IllegalStateException();
        checkForComodification();

    try {
    AbstractList.this.remove(lastRet);
    if (lastRet < cursor)
        cursor--;
    lastRet = -1;
    expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
    throw new ConcurrentModificationException();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接