Java 对于每个,使用迭代器vs For i
如果forEach获得Java 对于每个,使用迭代器vs For i,java,Java,如果forEach获得ConcurrentModificationException,为什么人们建议使用Iterator?在我的情况下,解决此异常的最佳方法是使用fori而不是foreach。 那么我有权利吗?如果我错了,请向我解释 例如: 例外 private void init() { addToCollection("Dog"); addToCollection("Cat"); showCollection(stringArrayLis
ConcurrentModificationException
,为什么人们建议使用Iterator
?在我的情况下,解决此异常的最佳方法是使用fori而不是foreach。那么我有权利吗?如果我错了,请向我解释 例如: 例外
private void init() {
addToCollection("Dog");
addToCollection("Cat");
showCollection(stringArrayList);
}
private void showCollection(List<String> collection) {
for (String s : collection) {
if (s.equals("Dog")){
collection.remove(s);
}
}
}
private void addToCollection(String value) {
stringArrayList.add(value);
}
}
private void init(){
添加到集合(“狗”);
添加到集合(“Cat”);
showCollection(stringArrayList);
}
私有void showCollection(列表集合){
用于(字符串s:集合){
如果(s.等于(“狗”)){
收集。移除;
}
}
}
私有void addToCollection(字符串值){
stringArrayList.add(值);
}
}
没有:
private void init() {
addToCollection("Dog");
addToCollection("Cat");
showCollection(stringArrayList);
}
private void showCollection(List<String> collection) {
for (int i = 0; i < collection.size(); i++) {
if (collection.get(i).equals("Dog")){
collection.remove(i);
}
}
}
private void addToCollection(String value) {
stringArrayList.add(value);
}
private void init(){
添加到集合(“狗”);
添加到集合(“Cat”);
showCollection(stringArrayList);
}
私有void showCollection(列表集合){
对于(int i=0;i
用于i
在索引的帮助下进行迭代时,不会得到ConcurrentModificationException
,因为这种情况下无法检测到。但发生的情况是,每次删除对象时,循环都会跳过一个对象,因为删除时索引会调整,但i
不会。如果在移除对象后减少i
,它将按预期工作
for (int i = 0; i < collection.size(); i++) {
if (collection.get(i).equals("Dog")){
collection.remove(i);
i--;
}
}
对于i
在索引的帮助下进行迭代时,不会得到ConcurrentModificationException
,因为这种情况下无法检测到。但发生的情况是,每次删除对象时,循环都会跳过一个对象,因为删除时索引会调整,但i
不会。如果在移除对象后减少i
,它将按预期工作
for (int i = 0; i < collection.size(); i++) {
if (collection.get(i).equals("Dog")){
collection.remove(i);
i--;
}
}
开发时有一条“规则”:永远不要修改正在循环的内容。如果在集合中循环,则不应在循环中修改它!如果要在循环中修改集合,请找到一种通过其他内容(如集合的副本或迭代器)进行循环的方法
遵守此规则的原因是为了避免错误。您可以创建一些黑客/技巧,以允许您修改正在循环的列表。但是强迫你不这样做,避免你错过你的黑客和创建一个错误的时间
在您的情况下,当您为每个循环执行一次测试时,系统能够看到您不遵守上述规则。所以它给你带来了一个例外
当您使用索引执行for循环时。系统无法检测到您修改了循环中的集合。但您仍然会遇到问题,因为您将删除集合中的项,但不会相应地修改索引,因此会跳过一些值。在这里,您可以编写一个“hack”,每次删除项目时都修改索引,但我强烈建议不要这样做。为了遵守上述规则,如果使用索引进行循环,请不要在循环中修改它
唯一好的方法是使用迭代器。此对象旨在允许在循环期间进行修改
开发时有一条“规则”:永远不要修改正在循环的内容。如果在集合中循环,则不应在循环中修改它!如果要在循环中修改集合,请找到一种通过其他内容(如集合的副本或迭代器)进行循环的方法
遵守此规则的原因是为了避免错误。您可以创建一些黑客/技巧,以允许您修改正在循环的列表。但是强迫你不这样做,避免你错过你的黑客和创建一个错误的时间
在您的情况下,当您为每个循环执行一次测试时,系统能够看到您不遵守上述规则。所以它给你带来了一个例外
当您使用索引执行for循环时。系统无法检测到您修改了循环中的集合。但您仍然会遇到问题,因为您将删除集合中的项,但不会相应地修改索引,因此会跳过一些值。在这里,您可以编写一个“hack”,每次删除项目时都修改索引,但我强烈建议不要这样做。为了遵守上述规则,如果使用索引进行循环,请不要在循环中修改它
唯一好的方法是使用迭代器。此对象旨在允许在循环期间进行修改
按照这个例子。此处已中断,因为您调用下一个迭代器的次数太多
对ForEach
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));
这里不会被打破。并为ForEach添加一个点
如您所见,for-each构造与
仿制药。它保留了所有类型的安全性,同时移除了
剩余的杂乱。因为不必声明迭代器,所以
不必为它提供通用声明
作为个人意见。这取决于何时使用for和foreach。一切都是相对的。但是当这个bug发生时,ForEach为您节省了大量调试时间
如果要修改循环内的集合,请使用CopyOnWriteArrayList
ArrayList的一种线程安全变体,其中包含所有变异操作
(添加、设置等)通过创建
底层数组
这通常成本太高,但可能比
当遍历操作的数量远远超过突变时的替代方案,以及
当您还不能或不想同步遍历时,此选项非常有用
需要排除并发线程之间的干扰
按照这个例子。此处已中断,因为您调用下一个迭代器的次数太多
五
// BROKEN - throws NoSuchElementException!
for (Iterator i = suits.iterator(); i.hasNext(); )
for (Iterator j = ranks.iterator(); j.hasNext(); )
sortedDeck.add(new Card(i.next(), j.next()));
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));