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和
方法中,缺点是我们必须迭代两次。首先,我们在foor循环中迭代,寻找与删除条件匹配的对象,一旦找到它,我们要求将其从原始集合中删除,这意味着需要进行第二次迭代来查找该项,以便删除它李>removeAll
- 我认为值得一提的是,
接口的remove方法在Javadocs中被标记为“可选”,这意味着如果调用remove方法,可能会有Iterator
实现抛出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);
}
}