从ArrayList中删除一个对象

4

我想从ArrayList中删除长度等于传递整数的元素。我的代码如下所示。运行时,程序在使用remove()方法的行中抛出UnsupportedOperationException。实际上,这是一个codingbat问题。

public static List<String> wordsWithoutList(String[] words, int len) {    
    List<String> list = new ArrayList<String>();

    list = Arrays.asList(words);

    for(String str : list) {
        if(str.length() == len) {
            list.remove(str);
        }
    }
    return l;       
}

好的,你有什么问题? - simchona
我想知道为什么会抛出上述异常。 - h-rai
你应该将 (List<String>) Arrays.asList(words); 进行强制类型转换。 - aviad
当您正在迭代同一列表时,无法从列表中删除元素。 - Nagaraju Badaeni
1个回答

10
asList 返回的列表不是一个 ArrayList,它不支持修改。
你需要做的是:
public static List<String> wordsWithoutList(String[] words, int len) {

    List<String> l = new ArrayList<String>( Arrays.asList(words) );

    for( Iterator<String> iter = l.iterator(); iter.hasNext(); ){
        String str = iter.next();
        if(str.length()==len){
            iter.remove();
        }
    }
    return l;       
}

所以需要做两件事情:

  • 使用ArrayList构造器对asList返回的数组进行可修改的复制。
  • 使用迭代器的remove方法以避免ConcurrentModificationException异常。

有人指出这种方法可能效率较低,因此一个更好的替代方案是:

List<String> l = new ArrayList<String>(str.length());
                                   //  ^^ initial capacity optional
for( String str : words )
    if( str.length()!=len)
        l.add(str);

return l;

1
好奇,这是一个好的做法吗(修改您正在迭代的列表)?还是应该创建一个新列表,在其中添加我们需要的元素并返回那个新的ArrayList? - zengr
2
我认为创建一个新列表并向其中添加项目更加清晰。 - SimonC
@zengr 任何一种策略都可以,使用 ArrayList 从中间删除项目会移动列表中的所有后续项目,因此如果要删除许多项目或列表很大,则最好使用复制策略。 - trutheality
@trutheality 你的代码运行得很好,但是当我用以下代码替换你的for循环时,它会抛出ConcurrentModificationException异常。你能告诉我为什么吗?因为在我的理解中,从对象中删除一个对象的语法是正确的,逻辑也是有效的,但它仍然会抛出异常。谢谢for(String str: l){ if(str.length()==len){ l.remove(str); } } - h-rai
1
@zengr 我的观点是,这绝对不是一种不好的做法,因为这正是迭代器的add和remove方法的用途。 - trutheality
@nick-s 这就是为什么我使用迭代器的原因:当你像这样迭代一个列表时,它内部使用自己的迭代器,你不能在循环中使用列表的remove或add方法,因为迭代器需要知道下一个元素在哪里--如果你被允许删除它,或在它前面添加一个元素,你可能会破坏迭代器。 - trutheality

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