从集合删除元素,而迭代从集合删除元素,而迭代(Remove elements from collec

2019-05-13 19:30发布

据我所知,有两种方法:

  1. 遍历集合的副本
  2. 使用实际征收的迭代器

例如,

List<Foo> fooListCopy = new ArrayList<Foo>(fooList);
for(Foo foo : fooListCopy){
    // modify actual fooList
}

Iterator<Foo> itr = fooList.iterator();
while(itr.hasNext()){
    // modify actual fooList using itr.remove()
}

是否有任何理由更喜欢一种方法比其他(如喜欢的可读性的原因很简单,第一种方法)?

Answer 1:

让我举一些替代品的几个例子,以避免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")));

收集和删除

第一种技术包括收集所有我们想要删除的对象(例如,使用for循环的增强),我们完成迭代后,我们会删除所有找到的对象。

ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
    if(book.getIsbn().equals(isbn)){
        found.add(book);
    }
}
books.removeAll(found);

这是假设你想要做的操作是“删除”。

如果你想“增加”这种做法也将工作,但我会假设你会遍历不同的集合,以确定您要添加到第二个集合,然后发出一个什么样的元素addAll在最后方法。

使用的ListIterator

如果您在操作列表,另一种方法包括使用ListIterator具有用于删除和添加项目的迭代过程本身的支持。

ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
    if(iter.next().getIsbn().equals(isbn)){
        iter.remove();
    }
}

同样,我用本例中的“删除”方法上面这是你的问题似乎有什么暗示,但是你也可以使用该add的方法来迭代过程中增加新的元素。

使用JDK> = 8

对于那些使用Java 8或上级版本的工作,有一对夫妇,你可以用它来利用它的其他技术。

你可以使用新的removeIf的方法Collection的基类:

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());

在最后这种情况下,过滤元件从集合中,重新分配的原始参考过滤收集(即books = filtered )或所使用的过滤收集removeAll从原始集合所找到的元件(即books.removeAll(filtered) )。

使用子表或子

还有其他的替代方案以及。 如果列表进行排序,并要删除连续元素,你可以创建一个子表,然后将其清除:

books.subList(0,5).clear();

由于子列表是由原始列表支持,这将是移除元素的这个子集合的有效方式。

类似的东西可以用有序集合来实现NavigableSet.subSet法或任何提供有切片的方法。

注意事项:

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

  • 在收集和removeAl技术也适用于任何集合(集合,列表,集等)。
  • ListIterator技术显然只是与名单的作品,前提是他们给出ListIterator实现提供支持,添加和删除操作。
  • Iterator方法将与任何类型的集合的工作,但它仅支持删除操作。
  • 随着ListIterator / Iterator接近显而易见的好处是不必复制任何东西,因为我们删除,因为我们迭代。 所以,这是非常有效的。
  • 在JDK 8流例如没有实际删除任何东西,但找了所需的元素,然后我们替换为新的一个原始集合的参考,让老被垃圾收集。 所以,我们在收集循环只有一次,这将是有效的。
  • 在收集和removeAll方法的缺点是,我们必须重复两次。 首先我们反复在福尔环找一个对象,符合我们的拆除标准,一旦我们找到了,我们要求从原来的集合,这将意味着第二次迭代工作,以寻找这个项目将其删除去掉它。
  • 我认为这是值得一提的是,中remove方法Iterator接口被标记为的Javadoc“可选”,这意味着,有可能是Iterator实现抛出UnsupportedOperationException ,如果我们调用remove方法。 因此,我会说这种方法比别人少安全的,如果我们不能保证去除元素的迭代器支持。


Answer 2:

是否有任何理由更喜欢一种方法比其他

第一种方法将工作,但复制列表明显的开销。

第二种方法是行不通的,因为许多容器不迭代过程中允许修改。 这包括ArrayList

如果只修改是删除当前元素,您可以通过使用使第二种方法工作itr.remove()即,使用迭代器remove()方法,而不是容器的)。 这将是我的首选方法,用于支持迭代器remove()



Answer 3:

在Java 8,还有另一种方法。 收藏#removeIf

例如:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

list.removeIf(i -> i > 2);


Answer 4:

只有第二种方法会奏效。 您可以使用迭代过程中修改集合iterator.remove()只。 所有其他的企图将导致ConcurrentModificationException



Answer 5:

你不能做第二个,因为即使你使用remove()上的方法迭代器 , 你会得到抛出的异常 。

就个人而言,我宁愿先为所有Collection的情况下,尽管增加了偷听创建新的Collection ,我觉得其他开发人员在编辑过程不那么容易出错。 在某些集合实现,迭代器remove()的支持,对其他事实并非如此。 您可以在文档的阅读更多迭代 。

第三种方法,是创建一个新的Collection ,遍历原来,和第一的所有成员加入Collection到第二Collection所有为删除。 根据大小Collection和删除的数量,这可能显著节省内存,相对于第一种方式时。



Answer 6:

我会选择第二个,你不必做内存的拷贝和迭代器工作更快。 所以你节省内存和时间。



Answer 7:

还有一个简单的解决方案,以“迭代”一个Collection和删除每个项目。

List<String> list = new ArrayList<>();
//Fill the list

它只是conciste上循环,直到列表为空,并在每次迭代中,我们删除了第一个元素remove(0)

while(!list.isEmpty()){
    String s = list.remove(0);
    // do you thing
}

我不认为这有比作任何改进Iterator ,它仍然需要有一个可变的列表,但我喜欢这个解决方案的简单性。



Answer 8:

为什么不呢?

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

如果这是一个地图,而不是一个列表,你可以使用键集()



文章来源: Remove elements from collection while iterating