Java为每个循环工作
我当时正在做某项任务,根据我的判断,我无意中做了一些错误,但代码执行并提供了正确的结果。我有点惊讶,并在脑海中有一个问题,所有这些对于每个循环是如何工作的。 示例(示例程序) 现在我只想知道上面引用的each for each循环后面发生了什么。Java为每个循环工作,java,loops,foreach,Java,Loops,Foreach,我当时正在做某项任务,根据我的判断,我无意中做了一些错误,但代码执行并提供了正确的结果。我有点惊讶,并在脑海中有一个问题,所有这些对于每个循环是如何工作的。 示例(示例程序) 现在我只想知道上面引用的each for each循环后面发生了什么。 我想知道技术方面的问题,我知道我不能为每个循环修改集合,但在上面提到的某些情况下,它起作用了。为什么?对于实现的类,每个循环都有可能。这也意味着您可以自己创建类,用于每个循环,这非常方便 此接口强制您实现一个方法iterator(),该方法返回一个it
我想知道技术方面的问题,我知道我不能为每个循环修改集合,但在上面提到的某些情况下,它起作用了。为什么?对于实现的类,每个循环都有可能。这也意味着您可以自己创建类,用于每个循环,这非常方便 此接口强制您实现一个方法
iterator()
,该方法返回一个iterator
。然后for-each循环只检索该迭代器,并使用hasNext()
和next()
对其进行迭代。就像你自己做的一样
删除的问题是,当您使用for-each循环,然后从列表中删除一个元素时,构造的迭代器将不知道有关该更改的任何信息,并且将出现ConcurrentModificationException
但是如果您直接调用Iterator.remove()
,迭代器将知道该更改并能够处理它
同时避免迭代器和异常的一个常见小技巧是执行以下操作:
List<Object> objects = new ArrayList<Object>();
for (Object object : new ArrayList<Object>(objects)) {
objects.remove(object);
}
List objects=new ArrayList();
用于(对象:新ArrayList(对象)){
对象。移除(对象);
}
因此,您可以创建该列表的临时副本,对其进行迭代,但对原始列表调用remove。这是正确的。您不能修改正在使用“foreach”循环进行迭代的集合的值,为此,您必须使用集合的迭代器。当然,向与您当前正在遍历的列表完全不同的列表中添加一些内容并不是问题,就像您对行mylist=new ArrayList()所做的那样代码>即使变量仍然具有相同的名称,它将指向一个完全不同的列表
您无法向当前正在“遍历”的列表中添加某些内容的原因是,该列表的内部实现可能无法确保您仍然获得与预期相同的元素顺序,尤其是不是所有剩余元素。
如果您设想您使用的是一个排序列表,那么这一点最容易理解:您放入了一个新元素,但您是否看到该元素是未定义的,因为它取决于您所在的位置和插入的内容。由于Java不知道您对此是否满意,因此它选择了安全的方法并抛出了一个异常
但是,有些列表能够在遍历过程中进行修改,大多数列表的每个循环的并发列表将通过迭代器在内部转换为循环的并发列表
for (String output : mylist)
{
System.out.println(output);
mylist = new ArrayList<String>(); //It worked
mylist.add(output);
}
它说,如果您在迭代过程中修改列表,而不是使用迭代器自己的remove方法,列表将抛出ConcurrentModificationException,这就是下面的工作原理
for (Iterator iterator2 = mylist.iterator(); iterator2.hasNext();)
{
String string = (String) iterator2.next();
System.out.println(string);
iterator2.remove(); //It worked but if I used the same thing to remove element from original list it threw exception.
}
现在我只想知道每个人背后都发生了什么
上面引用的循环
这会将splitted
数组中的每个output
字符串添加到mylist
列表中
2. for (String output : mylist)
{
System.out.println(output);
mylist = new ArrayList<String>(); //It worked
mylist.add(output);
}
其中Expression
必须是java.lang.Iterable
的实例或数组。因此,for:each
循环的等价于:
Iterator<String> iterator = mylist.iterator();
while (iterator.hasNext()) {
System.out.println(output);
mylist = new ArrayList<String>(); //It worked
mylist.add(output);
}
因此,即使在每次迭代时创建新的ArrayList
实例并将它们分配给mylist
,从原始mylist
获得的迭代器仍将引用原始mylist
,并将继续迭代原始mylist
的元素。迭代器保留对创建它的列表的引用。赋值mylist=new ArrayList()
对迭代器处理的数据没有影响,因为它更改变量mylist
,而不是列表本身
3. for (String output : mylist)
{
System.out.println(output);
mylist.add(output); // After this line it threw exception java.util.ConcurrentModificationException
}
下面的语句解释了这种行为。它是从Arraylist
doc:
这个类的迭代器和listIterator方法返回的迭代器是快速失效的:如果在迭代器创建后的任何时候,列表在结构上被修改,除了通过迭代器自己的remove或add方法,迭代器将抛出ConcurrentModificationException。因此,在面对并发修改时,迭代器会快速、干净地失败,而不是在将来的不确定时间冒着任意、不确定行为的风险
上面的语句还解释了这个for循环的行为:列表
可以在迭代列表时由迭代器自己的remove或add方法在结构上进行修改。创建这个副本是愚蠢的。只需使用迭代器遍历ArrayList(无论如何都要这样做,因为foreach就是这样做的),就可以添加和删除项,而无需产生任何错误,也无需创建副本。如果你真的需要同时做这些事情,那么就有一个同时做的清单,正好是为了这个目的。@two我们生活在2013年。创建列表副本在99%的情况下都没有问题。我认为它比使用迭代器更容易阅读,在这些情况下,我喜欢使用这个技巧。如果你认为它很愚蠢,好吧,不要用它。我还认为这是对问题中描述的问题的进一步解释……这是一个完全无用的操作,它还绕过了Java中称为ConcurrentModificationException的警告机制。因此,它不仅没有必要,而且还隐藏了潜在的bug。如果有一个简单的替代品,为什么要使用这样的东西呢?这是如何引入任何可能的bug的?这是一个完美的选择
for (String output : mylist)
{
System.out.println(output);
mylist.add(output); // After this line it threw exception java.util.ConcurrentModificationException
}
for (Iterator iterator2 = mylist.iterator(); iterator2.hasNext();)
{
String string = (String) iterator2.next();
System.out.println(string);
iterator2.remove(); //It worked but if I used the same thing to remove element from original list it threw exception.
}
1. for (String output : splitted)
{
mylist.add(output);
}
2. for (String output : mylist)
{
System.out.println(output);
mylist = new ArrayList<String>(); //It worked
mylist.add(output);
}
for ( FormalParameter : Expression )
Statement
Iterator<String> iterator = mylist.iterator();
while (iterator.hasNext()) {
System.out.println(output);
mylist = new ArrayList<String>(); //It worked
mylist.add(output);
}
public Iterator<E> iterator() {
return new Itr();
}
3. for (String output : mylist)
{
System.out.println(output);
mylist.add(output); // After this line it threw exception java.util.ConcurrentModificationException
}
4. for (Iterator iterator2 = mylist.iterator(); iterator2.hasNext();)
{
String string = (String) iterator2.next();
System.out.println(string);
iterator2.remove(); //It worked but if I used the same thing to remove element from original list it threw exception.
}