通过之前的介绍我们知道通过迭代器来遍历单例集合的操作仍然需要借助于循环结构。而且我们知道在单例集合中调用iterator方法返回的Iterator对象中还有一个remove方法我们没有介绍,它的作用是删除容器中的元素。说道这里应该有人会发现一个很明显的问题,那就是在单例集合中我们不是就已经定义过一个remove方法了吗,为什么还要在迭代器中定义一个remove方法呢?这不是多此一举吗?
为了解决这个问题,我们首先要解决一个问题——在单例集合中能否在循环结构中对元素进行增删操作。答案自然是不行的,那为为什么?接下来我们进入分析。
首先创建一个单例集合容器list,这个容器用ArrayList容器类来进行实现,因此它的元素具有索引,我们可以通过索引对它的元素进行操作。显然,在我们通过for循环来遍历元素之前对容器llist中的元素进行增删操作是没有问题的,但是现在我们想在进行遍历的同时对容器中的元素进行增删操作。
一、删除元素。
如果我们在遍历元素的时候删除了元素中指定位置的元素会出现什么现象呢。我们用一个实例来进行说明。在下面的这个代码中,我们将a、b、c、d四个元素添加到了容器list中,在遍历其中的元素时我们打算删除索引为2的元素,也就时删除元素c,这个是我们期望得到的结果。但是从执行结果来看,我们同时删除了元素c和d,这是为什么呢?因为当我们第一次删除了索引为2的元素时,容器的大小就发生改变了,也就是list.size的值从4变成了3,这时在变化了的容器容器中,元素d向前移动了一个位置,它的索引变成了2,所以再执行循环结构,自然会将他删除。也就是说这个代码无法完成我们只删除元素c的需求。当然,要完成我们的需求可以对这个代码做出简单的修改,在执行删除的部分添加判断条件,将代码改为
if(c.eauals(list.get(i)){
list.remove(i);
}
这样显然时能够达到我们的要求的,可是如果要删除多个元素,显然不会是一种有效的方法,因此这种写法也不可取。
package com.container.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorRemoveTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (int i = 0; i < list.size(); i++) {
list.remove(2);//改变数据结果
//list.add("dd");死循环
System.out.println(list.get(i));
}
}
}
二、增加元素
既然删除元素不可以,那么相对的在通过循环来遍历容器中的元素的同时往容器中增加元素显然而也是不可以的 。不过我们自然不信邪,抱着尝试弄死系统的态度我们浅浅尝试以下如果非要在遍历元素的时候向容器中添加元素又会发生什么样的情况呢?我们仍然以list容器为例子,在遍历元素时我们在for循环中添加元素dd,代码展示如下。
根据运行结果我们发现代码陷入了死循环,这是为什么呢?在我们看来这个代码应该不具备死循环的条件才对。那么真的不具备吗?其实当我们在for循环中添加元素的时候,容器的大小就已经发生改变了,也就是说每执行一次循环list.size()的值都会加一,那么用来进行判断是否进行循环的变量i的值增加一,list.size()的值也会增加一,所以i的值永远比list.size()的值小。循环条件一直满足,所以循环一直执行。
package com.container.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorRemoveTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (int i = 0; i < list.size(); i++) {
//list.add("dd");死循环
System.out.println(list.get(i));
}
}
}
通过上面的介绍我们知道,通过普通的循环结构去遍历容器中的元素时是不能对容器中的元素进行删除操作的。那么如果我们想要在遍历元素的同时对元素进行删除操作可不可以呢?答案是可以。这里只需要我们采用迭代器来遍历元素中的元素就可以在遍历元素的同时对元素进行删除操作。能这样做的原因是用迭代器遍历元素的的时候设计元素索引的应用,而且判断循环是否执行的条件也与元素的索引无关。
但是这里有两个注意的点,第一是在通过迭代器来遍历容器中的元素的时候不能重复调用next方法,因为next方法不仅会返回当前位置的元素,还会将指针移动到下一个元素的位置。如果多次调用next方法,极有可能会导致容器中的元素丢失,无法正常遍历容器中的元素。另一个需要注意的点是,通过迭代器迭代元素时是不能向容器中添加元素的,虽然这么写在编译时不会报错,但是运行时是不被允许的。
此外,我们之前就说过增强for循环即for-each循环其实也算是迭代器,所以用它来遍历容器中的元素时也可以调用remove方法来对容器中的元素进行删除操作,但仍然不可以添加元素。
package com.container.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorRemoveTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (int i = 0; i < list.size(); i++) {
//list.remove(2);改变数据结果
//list.add("dd");死循环
System.out.println(list.get(i));
}
System.out.println("_____________________________");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
//不能在一个迭代器种多次调用next()。
String value = iterator.next();
if("c".equals(value)){
iterator.remove();
}
}
for(Iterator<String> it = list.iterator();it.hasNext(); ){
String va = it.next();
System.out.println(va);
//list.add("ddd");//编译不报错,但运行会报错,在迭代器包括增强for循环中不能添加元素
}
}
}