Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 迭代时从集合中删除元素_Java_Collections_Iteration - Fatal编程技术网

Java 迭代时从集合中删除元素

Java 迭代时从集合中删除元素,java,collections,iteration,Java,Collections,Iteration,好的,有两种方法: 迭代集合的副本 使用实际集合的迭代器 比如说, List<Foo> fooListCopy = new ArrayList<Foo>(fooList); for(Foo foo : fooListCopy){ // modify actual fooList } List-doulistcopy=new-ArrayList(doulist); 对于(Foo-Foo:doulistcopy){ //修改实际愚人 } 及 Iterator it

好的,有两种方法:

  • 迭代集合的副本
  • 使用实际集合的迭代器
  • 比如说,

    List<Foo> fooListCopy = new ArrayList<Foo>(fooList);
    for(Foo foo : fooListCopy){
        // modify actual fooList
    }
    
    List-doulistcopy=new-ArrayList(doulist);
    对于(Foo-Foo:doulistcopy){
    //修改实际愚人
    }
    

    Iterator itr=whoolist.Iterator();
    while(itr.hasNext()){
    //使用itr.remove()修改实际愚人
    }
    
    是否有任何理由选择一种方法而不是另一种方法(例如,出于可读性的简单原因而选择第一种方法)

    有什么理由选择一种方法而不是另一种方法吗

    第一种方法可以工作,但复制列表的开销很明显

    第二种方法不起作用,因为许多容器不允许在迭代期间进行修改


    如果唯一的修改是删除当前元素,那么可以使用(即,使用迭代器的
    remove()
    方法,而不是容器的方法)使第二种方法起作用对于支持
    remove()

    的迭代器,这是我首选的方法,只有第二种方法可以工作。您可以在迭代期间仅使用
    iterator.remove()
    修改集合。所有其他尝试都会导致
    ConcurrentModificationException

    我会选择第二种,因为您不必复制内存,迭代器的工作速度更快。因此,您可以节省内存和时间。

    让我举几个例子,并提供一些替代方案,以避免出现
    ConcurrentModificationException

    假设我们有以下藏书

    List<Book> books = new ArrayList<Book>();
    books.add(new Book(new ISBN("0-201-63361-2")));
    books.add(new Book(new ISBN("0-201-63361-3")));
    books.add(new Book(new ISBN("0-201-63361-4")));
    
    同样,我在上面的示例中使用了“remove”方法,这似乎是您的问题所暗示的,但是您也可以使用它的
    add
    方法在迭代过程中添加新元素

    使用JDK>=8

    对于那些使用Java8或更高版本的用户,您可以使用一些其他技术来利用它

    您可以在
    集合
    基类中使用新的
    removeIf
    方法:

    ISBN other = new ISBN("0-201-63361-2");
    books.removeIf(b -> b.getIsbn().equals(other));
    
    或者使用新的流API:

    ISBN other = new ISBN("0-201-63361-2");
    List<Book> filtered = books.stream()
                               .filter(b -> b.getIsbn().equals(other))
                               .collect(Collectors.toList());
    
    由于子列表由原始列表支持,因此这将是删除此元素子集合的有效方法

    使用
    NavigableSet.subSet
    方法或其中提供的任何切片方法,可以通过排序集实现类似的功能

    注意事项:

    你使用什么方法可能取决于你打算做什么

    • collect和
      removeAl
      技术适用于任何集合(集合、列表、集合等)
    • ListIterator
      技术显然只适用于列表,前提是它们给定的
      ListIterator
      实现提供了对添加和删除操作的支持
    • 迭代器方法可用于任何类型的集合,但它只支持删除操作
    • 使用
      列表迭代器
      /
      迭代器
      方法的明显优势是不必复制任何内容,因为我们在迭代时会删除任何内容。所以,这是非常有效的
    • JDK 8 streams示例实际上没有删除任何内容,而是查找所需的元素,然后我们用新的集合引用替换了原始的集合引用,并让旧的集合被垃圾收集。因此,我们只在集合上迭代一次,这将是有效的
    • 在collect和
      removeAll
      方法中,缺点是我们必须迭代两次。首先,我们在foor循环中迭代,寻找与删除条件匹配的对象,一旦找到它,我们要求将其从原始集合中删除,这意味着需要进行第二次迭代来查找该项,以便删除它
    • 我认为值得一提的是,
      Iterator
      接口的remove方法在Javadocs中被标记为“可选”,这意味着如果调用remove方法,可能会有
      Iterator
      实现抛出
      UnsupportedOperationException
      。因此,如果我们不能保证迭代器支持删除元素,我认为这种方法不如其他方法安全

    您不能执行第二个操作,因为即使在上使用
    remove()
    方法

    就我个人而言,我更喜欢所有
    集合
    实例中的第一个,尽管在创建新的
    集合
    时会有额外的杂音,但我发现其他开发人员在编辑过程中不太容易出错。在某些集合实现中,迭代器
    remove()
    受支持,而在其他实现中则不受支持。您可以在有关的文档中阅读更多内容

    第三种选择是创建一个新的
    集合
    ,对原始集合进行迭代,并将第一个
    集合
    的所有成员添加到第二个
    集合
    中,这些成员不可删除。根据
    集合的大小和删除的次数,与第一种方法相比,这可以显著节省内存

    为什么不是这个

    for( int i = 0; i < Foo.size(); i++ )
    {
       if( Foo.get(i).equals( some test ) )
       {
          Foo.remove(i);
       }
    }
    
    for(inti=0;i

    如果它是一个映射,而不是一个列表,那么可以在Java8中使用keyset()

    例如:

    List List=new ArrayList();
    增加第(1)款;
    增加(2);
    增加(3);
    移除列表(i->i>2);
    
    旧时最爱(它仍然有效):

    列表;
    对于(int i=list.size()-1;i>=0;--i)
    {
    if(list.get(i).contains(“bad”))
    {
    列表。删除(i);
    }
    }
    
    好处:

  • 它只在列表上迭代一次
  • 没有创建额外的对象,或其他不必要的复杂性
  • 尝试使用已删除项的索引没有问题,因为。。。好好想想
    只是好奇,你为什么要创作一本《傻瓜》呢
    ISBN other = new ISBN("0-201-63361-2");
    books.removeIf(b -> b.getIsbn().equals(other));
    
    ISBN other = new ISBN("0-201-63361-2");
    List<Book> filtered = books.stream()
                               .filter(b -> b.getIsbn().equals(other))
                               .collect(Collectors.toList());
    
    books.subList(0,5).clear();
    
    for( int i = 0; i < Foo.size(); i++ )
    {
       if( Foo.get(i).equals( some test ) )
       {
          Foo.remove(i);
       }
    }
    
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    
    list.removeIf(i -> i > 2);
    
    List<String> list;
    
    for(int i = list.size() - 1; i >= 0; --i) 
    {
            if(list.get(i).contains("bad"))
            {
                    list.remove(i);
            }
    }