【问题标题】:Remove multiple items from ArrayList during iterator在迭代器期间从 ArrayList 中删除多个项目
【发布时间】:2018-07-24 19:31:52
【问题描述】:

在使用迭代器迭代时从 ArrayList 中删除多个项目是否安全?

Iterator<String> iterator = nameList.iterator();
 while(iterator.hasNext()){
     String s = iterator.next();
     List<String> list = work(s);
     for (String s1 : list) {
        nameList.remove(s1);   
    }
}

work() 方法返回在 while 循环运行期间应从 nameList 中删除的名称列表。

【问题讨论】:

    标签: java arraylist iterator java-7


    【解决方案1】:

    不,不安全,可以抛出ConcurrentModificationException。您可以将所有要移除的元素收集到一个临时的List 中,然后在while 循环之后调用list.removeAll(tmpList) 执行移除。

    Iterator<String> iterator = nameList.iterator();
    List<String> removed = new ArrayList<>();
    while(iterator.hasNext()){
        String s = iterator.next();
        removed.addAll(work(s));
    }
    list.removeAll(removed);
    

    我意识到这可能会降低效率,因为您可能会在 Strings 上调用 work(s),而之前应该从 List 中删除。这可以通过将tempList 更改为Set 来改进,并且只为Strings 而不在Set 中调用work(s)

    Iterator<String> iterator = nameList.iterator();
    Set<String> removed = new HashSet<>();
    while(iterator.hasNext()){
        String s = iterator.next();
        if (!removed.contains(s)) {
            removed.addAll(work(s));
        }
    }
    list.removeAll(removed);
    

    【讨论】:

    • 是的,避免调用应该在前一个循环中删除的字符串上的工作正是我想要做的。
    • 我将使用“已移除”集尝试您的想法。感谢您的建议。
    • 当然,那你就不需要手动处理Iterator了; for(String s: nameList) { if(!removed.contains(s)) removed.addAll(work(s)); } list.removeAll(removed);
    【解决方案2】:

    如果您使用故障安全的 ListIterator,您可以实现您的逻辑。下面是一个基本的例子:

    Set<String> removed = new HashSet<>();
        ArrayList<String> nameList = new ArrayList<String>();
    
                ListIterator<String> iterator = nameList.listIterator();
                 while(iterator.hasNext()){
                     String s = iterator.next();
                     if (!removed.contains(s)) {
            removed.addAll(work(s));
        }
    
                }
    
    
     nameList.removeAll(removed);
                     System.out.println(nameList);
    

    根据您的逻辑,您必须考虑性能。如果性能不是一个因素,您可以继续通过 ListIterator 从列表中添加/删除。

    【讨论】:

    • 仍然会抛出 ConcurrentModificationException
    • 只需使用 sysout 语句检查您获得的列表是否为空或其他任何内容。
    • @Jayanth 在ListIterator 上调用remove() 在每个迭代步骤中只调用一次就可以了,但在支持List 上调用removeAll 则不行。
    • 嗨@Thommy,可能会检查您是否正在从列表中删除一个已被删除的元素或其他什么...因为我的帖子只是为了让您了解如何使用 ListIterator。
    • @Jayanth 是的,这正是问题所在,删除一个作品,但我想在一次迭代中删除多个。我使用 Eran 的回答中的“解决方法”解决了这个问题。
    【解决方案3】:

    正如前面的回答所说,从迭代列表中删除一个项目是不安全的。这是一个抛出ConcurrentModificationException的代码:

    List<String> list = new ArrayList<>(Arrays.asList("1", "2", "3"));
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String s = iterator.next();
        list.remove("1");
    }
    

    【讨论】:

      猜你喜欢
      • 2013-08-31
      • 1970-01-01
      • 2012-11-30
      • 2013-10-05
      • 2018-10-21
      • 2020-06-22
      • 2020-03-18
      • 1970-01-01
      • 2012-05-29
      相关资源
      最近更新 更多