Mic*_*ick 575 java foreach iterator loops
在Java中,使用foreach循环遍历集合时,对集合调用remove是否合法?例如:
List<String> names = ....
for (String name : names) {
// Do something
names.remove(name).
}
Run Code Online (Sandbox Code Playgroud)
作为附录,删除尚未迭代的项目是否合法?例如,
//Assume that the names list as duplicate entries
List<String> names = ....
for (String name : names) {
// Do something
while (names.remove(name));
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*ark 879
要在迭代时安全地从集合中删除,您应该使用Iterator.
例如:
List<String> names = ....
Iterator<String> i = names.iterator();
while (i.hasNext()) {
String s = i.next(); // must be called before you can call i.remove()
// Do something
i.remove();
}
Run Code Online (Sandbox Code Playgroud)
从Java文档:
此类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出ConcurrentModificationException.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.
也许许多新手不清楚的事实是,使用for/foreach构造迭代列表会隐式创建一个必然无法访问的迭代器.此信息可在此处找到
Jar*_*aus 160
你不想那样做.它可能会导致未定义的行为,具体取决于集合.您想直接使用Iterator.尽管每个构造都是语法糖并且实际上使用了迭代器,但它会从代码中隐藏它,因此您无法访问它以进行调用Iterator.remove.
如果在迭代正在进行中以除调用此方法之外的任何方式修改基础集合,则未指定迭代器的行为.
而是编写你的代码:
List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
// Do something
it.remove();
}
Run Code Online (Sandbox Code Playgroud)
请注意代码调用Iterator.remove,而不是List.remove.
附录:
即使您要删除尚未迭代的元素,您仍然不想修改集合,然后使用Iterator.它可能会以令人惊讶的方式修改集合,并影响其未来的操作Iterator.
Yis*_*hai 60
"增强for循环"的java设计是不将迭代器暴露给代码,但安全删除项的唯一方法是访问迭代器.所以在这种情况下你必须做旧学校:
for(Iterator<String> i = names.iterator(); i.hasNext();) {
String name = i.next();
//Do Something
i.remove();
}
Run Code Online (Sandbox Code Playgroud)
如果在实际代码中增强的for循环确实值得,那么你可以将项添加到临时集合并在循环后调用列表中的removeAll.
编辑(补遗):不,迭代时在iterator.remove()方法之外以任何方式更改列表都会导致问题.解决这个问题的唯一方法是使用CopyOnWriteArrayList,但这确实是出于并发问题.
最简单的(就代码行而言)删除重复项的方法是将列表转储到LinkedHashSet中(如果需要,然后返回到List中).这样可以在删除重复项时保留插入顺序.
kta*_*lyn 59
for (String name : new ArrayList<String>(names)) {
// Do something
names.remove(nameToRemove);
}
Run Code Online (Sandbox Code Playgroud)
您names从原始列表中删除时克隆列表并遍历克隆.比最佳答案更清洁.
Ser*_*eim 27
我不知道迭代器,但是这是我今天要做的事情,从循环中的列表中删除元素:
List<String> names = ....
for (i=names.size()-1;i>=0;i--) {
// Do something
names.remove(i);
}
Run Code Online (Sandbox Code Playgroud)
这始终有效,可以用于其他语言或不支持迭代器的结构.
Cha*_*ana 23
是的,您可以使用for-each循环,为此,您必须维护一个单独的列表来保存删除项目,然后使用removeAll()方法从名称列表中删除该列表,
List<String> names = ....
// introduce a separate list to hold removing items
List<String> toRemove= new ArrayList<String>();
for (String name : names) {
// Do something: perform conditional checks
toRemove.add(name);
}
names.removeAll(toRemove);
// now names list holds expected values
Run Code Online (Sandbox Code Playgroud)
确保这不是代码异味。是否可以颠倒逻辑,做到“包容”而不是“排他”?
List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
// Do something
if (conditionToIncludeMet)
reducedNames.add(name);
}
return reducedNames;
Run Code Online (Sandbox Code Playgroud)
导致我进入此页面的情况涉及使用 indecies 循环遍历列表以从列表中删除元素的旧代码。我想重构它以使用 foreach 样式。
它循环遍历整个元素列表以验证用户有权访问哪些元素,并从列表中删除没有权限的元素。
List<Service> services = ...
for (int i=0; i<services.size(); i++) {
if (!isServicePermitted(user, services.get(i)))
services.remove(i);
}
Run Code Online (Sandbox Code Playgroud)
要扭转这种情况而不使用删除:
List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
if (isServicePermitted(user, service))
permittedServices.add(service);
}
return permittedServices;
Run Code Online (Sandbox Code Playgroud)
什么时候会首选“删除”?一个考虑因素是,是否给出一个大列表或昂贵的“添加”,并且与列表大小相比仅删除了一些。只进行少量删除可能比进行大量添加更有效。但就我而言,这种情况不值得进行这样的优化。
| 归档时间: |
|
| 查看次数: |
409142 次 |
| 最近记录: |