在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));
}
确保这不是代码的味道。有可能颠倒逻辑,“包容”而不是“排他”吗?
List<String> names = ....
List<String> reducedNames = ....
for (String name : names) {
// Do something
if (conditionToIncludeMet)
reducedNames.add(name);
}
return reducedNames;
将我引导到这个页面的情况涉及到使用indecies从List中删除元素循环遍历List的旧代码。我想重构它以使用foreach样式。
它循环遍历整个元素列表,以验证用户有权限访问哪些元素,并从列表中删除没有权限的元素。
List<Service> services = ...
for (int i=0; i<services.size(); i++) {
if (!isServicePermitted(user, services.get(i)))
services.remove(i);
}
要反转此操作而不使用remove:
List<Service> services = ...
List<Service> permittedServices = ...
for (Service service:services) {
if (isServicePermitted(user, service))
permittedServices.add(service);
}
return permittedServices;
什么时候“remove”更合适?一个考虑因素是,如果给定一个大列表或昂贵的“添加”,与列表大小相比,只删除了一些内容。只做少量的删除可能比大量的添加更有效。但在我的案例中,情况并不值得这样的优化。
你不会想这么做的。它可能导致未定义的行为,具体取决于集合。你想直接使用迭代器。虽然for每个构造都是语法糖,并且实际上使用了迭代器,但它对代码隐藏了迭代器,因此您无法访问它来调用iterator .remove。
迭代器的行为是
未指定,如果基础
属性时,将对集合进行修改
迭代正在以任何方式进行
除了调用这个方法。
相反,编写代码:
List<String> names = ....
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
// Do something
it.remove();
}
注意,代码调用Iterator。remove,而不是List.remove。
附录:
即使您正在删除一个尚未迭代的元素,您仍然不想修改集合,然后使用Iterator。它可能会以一种令人惊讶的方式修改集合,并影响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();
}
摘自Java文档:
该类的迭代器和listIterator返回的迭代器
方法是快速失败的:如果列表在任何地方被结构修改
方法创建迭代器后的任何时间
迭代器自己的remove或add方法时,迭代器将抛出
并发修改异常因此,面对并发
修改后,迭代器会快速而干净地失败,而不是
在不确定的时间冒着武断的、不确定的行为的风险
在未来。
也许许多新手不清楚的是,使用for/foreach构造隐式遍历列表会创建一个不可访问的迭代器。这些信息可以在这里找到