这个问题在这里已有答案:
在Java中,使用foreach循环遍历集合时,对集合调用remove是否合法?例如:
List<String> names = ....
for (String name : names) {
// Do something
names.remove(name).
}
作为附录,删除尚未迭代的项目是否合法?例如,
//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
// Do something
while (names.remove(name));
}
11 回答
要在迭代时安全地从集合中删除,您应该使用Iterator .
例如:
来自Java Documentation:
也许许多新手不清楚的事实是,使用for / foreach构造迭代列表会隐式创建一个必然无法访问的迭代器 . 这个信息可以在here找到
你不想那样做 . 它可能会导致未定义的行为,具体取决于集合 . 您想直接使用Iterator . 尽管每个构造都是语法糖并且实际上是使用迭代器,但它会从代码中隐藏它,因此您无法访问它以调用Iterator.remove .
而是编写你的代码:
请注意,代码调用
Iterator.remove
,而不是List.remove
.Addendum:
即使您要删除尚未迭代的元素,您仍然不想修改该集合,然后使用
Iterator
. 它可能会以令人惊讶的方式修改集合,并影响Iterator
上的未来操作 .“增强for循环”的java设计是不将迭代器暴露给代码,但安全删除项的唯一方法是访问迭代器 . 所以在这种情况下你必须做旧学校:
如果在实际代码中增强的for循环确实值得,那么你可以将项添加到临时集合并在循环后调用列表中的removeAll .
编辑(补遗):不,迭代时在iterator.remove()方法之外以任何方式更改列表都会导致问题 . 解决这个问题的唯一方法是使用CopyOnWriteArrayList,但这确实是出于并发问题 .
最简单的(就代码行而言)删除重复项的方法是将列表转储到LinkedHashSet中(如果需要,然后返回到List中) . 这样可以在删除重复项时保留插入顺序 .
克隆列表
names
并在从原始列表中删除时遍历克隆 . 比最佳答案更清洁 .我不知道迭代器,但是这是我今天要做的事情,从循环中的列表中删除元素:
这始终有效,可以用于其他语言或不支持迭代器的结构 .
是的,您可以使用for-each循环,为此,您必须维护一个单独的列表来保存删除项目,然后使用
removeAll()
方法从名称列表中删除该列表,那些说你不能安全地从集合中删除项目的人除了通过Iterator之外都不太正确,你可以使用其中一个并发集合(例如ConcurrentHashMap)安全地执行它 .
确保这不是代码味道 . 是否有可能扭转逻辑并“包容”而不是“排他”?
导致我访问此页面的情况涉及使用indecies循环访问List的旧代码,以从List中删除元素 . 我想重构它以使用foreach风格 .
它遍历整个元素列表以验证用户有权访问哪些元素,并从列表中删除没有权限的元素 .
要反转此操作而不使用删除:
何时“删除”是首选?一个考虑因素是如果gien是一个大的列表或昂贵的“添加”,与列表大小相比只有少数删除 . 仅执行一些删除而不是添加很多内容可能更有效 . 但在我的情况下,情况不值得这样的优化 .
如果要从列表中删除元素,最好使用Iterator
因为删除的源代码是
所以,如果你从列表中删除一个元素,列表将重组,另一个元素的索引将被更改,这可能会导致你想要发生的事情 .
使用
.remove()的Interator或
使用
的CopyOnWriteArrayList