【发布时间】:2010-12-03 01:13:57
【问题描述】:
虽然 for-each 循环有很多优点,但问题是,当您想要过滤(过滤意味着从列表中删除元素)列表时它不起作用,您能否请任何替换,因为即使遍历索引也不是不错的选择..
【问题讨论】:
虽然 for-each 循环有很多优点,但问题是,当您想要过滤(过滤意味着从列表中删除元素)列表时它不起作用,您能否请任何替换,因为即使遍历索引也不是不错的选择..
【问题讨论】:
如果你和我一样,不喜欢在迭代它的元素时修改集合,或者如果迭代器没有提供删除的实现,你可以使用临时集合来收集你想要删除的元素.是的,是的,与修改迭代器相比,它的效率较低,但对我来说,更清楚地了解发生了什么:
List<Object> data = getListFromSomewhere();
List<Object> filter = new ArrayList<Object>();
// create Filter
for (Object item: data) {
if (throwAway(item)) {
filter.add(item);
}
}
// use Filter
for (Object item:filter) {
data.remove(item);
}
filter.clear();
filter = null;
【讨论】:
我已经成功使用了
filter(java.util.Collection collection, Predicate predicate)
commons 集合中 CollectionUtils 的方法。
【讨论】:
“过滤”是什么意思?从列表中删除某些元素?如果是这样,您可以使用iterator:
for(Iterator<MyElement> it = list.iterator(); it.hasNext(); ) {
MyElement element = it.next();
if (some condition) {
it.remove();
}
}
更新(基于 cmets):
考虑以下示例来说明迭代器的工作原理。假设我们有一个包含“A”和“B”的列表:
A A B B A
我们想删除所有那些讨厌的Bs。因此,使用上面的循环,代码将如下工作:
element 指向第一个 A。element 指向第二个 A。element 指向第一个 B.remove()。迭代器计数器不会改变,它仍然指向 B 所在的位置(从技术上讲,这并不完全正确,但从逻辑上讲,它就是这样工作的)。如果你现在再次调用 remove(),你会得到一个异常(因为列表元素不再存在)。element指向第2个B,其余同#3element 指向第 3 个 A。更新 #2:remove() 操作在迭代器上确实是可选的 - 但只是因为它在基础集合上是可选的。这里的底线是 - 如果您的集合支持它(Java Collection Framework 中的所有集合都支持),那么迭代器也支持。如果您的收藏不支持它,那么您无论如何都不走运。
【讨论】:
remove() 在“当前”元素(从最后一个 next() 方法调用返回的元素)上调用,并且不会更改“当前”元素。下次调用 next() 将返回列表中的以下元素。
ChssPly76 的答案是正确的方法 - 但我对您在“遍历索引不是一个好的选择”背后的想法很感兴趣。在许多情况下——特别是常见的情况是ArrayList——它非常有效。 (事实上,在 arraylist 的情况下,我相信重复调用 get(i++) 比使用迭代器要快一些,尽管还远远不足以牺牲可读性)。
一般来说,如果有问题的对象实现了java.util.RandomAccess,那么通过索引访问顺序元素的速度应该与使用迭代器的速度大致相同。如果不是(例如LinkedList 将是一个很好的反例),那么您是对的;但不要立即放弃这个选项。
【讨论】:
ArrayList(或类似的),那么基于索引的访问将会快速(甚至比使用迭代器快一点),所以这是一个不错的选择。如果这是一个通用库方法,它可能采用各种列表,而您无法控制其实现 - 那么假设是不好的(尽管您仍然可以检查接口实现)。