如何从ArrayList中删除元素?

5

我已经向 ArrayList 中添加了数据,现在想通过删除其中的一些元素来更新该列表。

我在类型为 CartEntryArrayList 中拥有类似 1、2、3、4 的元素。

代码:

ArrayList<CartEntry> items = new ArrayList<CartEntry>();

public void remove(int pId)
{
    System.out.println(items.size());

    for(CartEntry ce : items)
    {
        if(ce.getpId() == pId)
        {
            items.remove(ce);
            //System.out.println(items.get(1));             
        }
    }   
    items.add(new CartEntry(pId));
}

购物车项目代码:

public long getpId() {
    return pId;
}

构造函数:

public CartEntry(long pId) {
    super();
    this.pId = pId;     
}

当我尝试运行这段代码时,它会报错:
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)

这里的pId是指定要从items中删除的项的参数。假设我想要删除具有2个数据的项目,我该怎么做?


1
你的代码出了什么问题? - Ross Drew
1
不要在没有迭代器的情况下删除。这是很危险的。 - Maroun
@MarounMaroun - 先生,我已经发布了我遇到的异常,以及如何实现迭代器? - Java Curious ღ
为什么在remove函数中又添加了CartEntry(pId):“items.add(new CartEntry(pId))?” - ray
只需按相反的顺序迭代列表 for(int i=items.count; i <=0; i--) - ray
@ray:没有真正的理由这样做,迭代器完全可以胜任: - Joachim Sauer
6个回答

14

你面临 ConcurrentModificationException 问题,因为你同时对同一个list进行两个操作。即同时循环和删除。

为了避免这种情况,使用迭代器,这可以保证你安全地从列表中删除元素。

一个简单的示例看起来像:

Iterator<CartEntry> it = list.iterator();
    while (it.hasNext()) {
        if (it.next().getpId() == pId) {
            it.remove();
            break;
        }
    }

1
非常棒的回答。每个人的答案都一样,而你多加了一行代码让我的程序变得简单易用,这就是一个简单的 break。谢谢。 - Java Curious ღ
@user2659972ღ:如果您知道没有两个CartEntry对象具有相同的ID,则中断不是必需的,而且只有在这种情况下才真正有用。 - Joachim Sauer
@JoachimSauer - 是的先生,但如果我不使用 break 并删除项目,则它可以工作,但之后我得到了与上述相同的错误,但问题项目已被删除。所以这就是为什么 break 对我有用。 - Java Curious ღ
1
如果你没有使用 break 仍然出现异常,那么你仍在使用 items.remove() 而不是 it.remove() - Joachim Sauer

3

你创建了一个类型为carEntry的ArrayList。因此,你需要创建一个类型为CarEntry的迭代器。

Iterator<CarEntry> it =  items.iterator();    
while(it.hasNext())
{
   if(it.next().getPId == PId)
   it.remove();
}

3
你的代码至少存在两个问题:
1. 你在迭代集合时调用了 `remove` 方法,如果在 `remove` 后继续迭代会导致 ConcurrentModificationException。解决方法有两种: - 在找到要删除的对象后停止迭代(添加 `break` 或 `return` 语句)或者 - 改用 Iterator它的 remove 方法 进行迭代。 2. 你在 `remove` 方法中添加了一个元素,这可能不是你想要的。

所以我会使用这段代码(假设在列表中只有一个给定id的CartEntry):

public void remove(int pId)
{
    for(CartEntry ce : items)
    {
        if(ce.getpId() == pId)
        {
            items.remove(ce);
            return;
        }
    }   
}

如果唯一标识的假设是不正确的,那么您需要使用Iterator方法:
public void remove(int pId)
{
    Iterator<CartEntry> it = items.iterator();
    while(it.hasNext())
    {
        CartEntry ce = it.next();
        if(ce.getpId() == pId)
        {
            it.remove();
        }
    }   
}

1

尝试,

public void remove(int pId){

Iterator<CartEntry> it = items.iterator();

 while(it.hasNext()) {
    CartEntry entry = it.next();
    if (entry.getpId() == pId) {
        it.remove();
    }
  }
}

1

enhanced-for(或称为 for each)循环用于迭代一个 Expression,该表达式是 Iterable<E> 或原始的 Iterable 的子类型,基本上相当于以下形式:

  for (I #i = Expression.iterator(); #i.hasNext(); ) {   
      VariableIdentifiers_opt TargetType Identifier = (TargetType) #i.next();
         Statement
   }

这在jls 14.14.2. The enhanced for statement部分中明确说明。

对于您的上下文,Expression是一个ArrayList。通过ArrayList的迭代器方法返回的迭代器是快速失败的:如果列表在迭代器创建后的任何时候以除迭代器自己的remove或add方法以外的任何方式进行结构修改,则迭代器将抛出ConcurrentModificationException

改用Iterator并使用它自己的remove()方法:

  Iterator<E>iterator = list.iterator();
  while(iterator.hasNext())
    if(iterator.next().equals(E))
      iterator.remove();

1
在CartEntry中实现.equals方法,然后使用ArrayList.remove(CartEntry)或循环遍历数组列表,找到满足某些条件的项目,标记索引,并在循环之后调用ArrayList.remove(index)。

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