迭代:
是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
重复执行一系列运算步骤,从前面的量依次求出后面的量的过程。此过程的每一次结果,都是由对前一次所得结果施行相同的运算步骤得到的。例如利用迭代法*求某一数学问题的解。
对计算机特定程序中需要反复执行的子程序*(一组指令),进行一次重复,即重复执行程序中的循环,直到满足某条件为止,亦称为迭代。
迭代器(Iterator)模式:
又叫做游标模式,它的含义是,提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
注意:Java的集合框架的集合类,有的时候也称为容器。
从定义上看,迭代器是为容器而生,它本质上就是一种遍历的算法。因为容器的实现千差万别,很多时候不可能知道如何去遍历一个集合对象的元素。Java为我们提供了使用迭代的接口,Java的所有集合类丢失进行迭代的。
简单的说,迭代器就是一个接口Iterator,实现了该接口的类就叫做可迭代类,这些类多数时候指的就是java.util包下的集合类。
总结:
迭代器,提供一种访问一个集合对象各个元素的途径,同时又不需要暴露该对象的内部细节。java通过提供Iterator和Iterable俩个接口来实现集合类的可迭代性,迭代器主要的用法是:首先用hasNext()作为循环条件,再用next()方法得到每一个元素,最后在进行相关的操作。
扩展资料
首先,创建了一个List的集合对象,并放入了俩个字符串对象,然后通过iterator()方法得到迭代器。iterator()方法是由Iterable接口规定的,ArrayList对该方法提供了具体的实现,在迭代器Iteartor接口中,有以下3个方法:
1、hasNext() 该方法英语判断集合对象是否还有下一个元素,如果已经是最后一个元素则返回false。
2、next() 把迭代器的指向移到下一个位置,同时,该方法返回下一个元素的引用。
3、remove() 从迭代器指向的Collection中移除迭代器返回的最后一个元素,该操作使用的比较少。
注意:从Java5.0开始,迭代器可以被foreach循环所替代,但是foreach循环的本质也是使用Iterator进行遍历的。
参考资料:百度百科——迭代器
参考资料:百度百科——迭代
for each语句是由iterator实现的,正如你所说,他们的不同之处就在于remove()方法上。
一般调用删除方法都是集合的方法,例如:
List list = new ArrayList();。
list.add(...);
list.remove(...);。
但是,如果在循环的过程中调用集合的remove()方法,就会导致循环出错,例如:
for(int i=0;i<list.size();i++){。
list.remove(...);。
循环过程中list.size()的大小变化了,就导致了错误。
所以,如果你想在循环语句中删除集合中的某个元素,就要用迭代器iterator的remove()方法,因为它的remove()方法不仅会删除元素,还会维护一个标志,用来记录目前是不是可删除状态,例如,你不能连续两次调用它的remove()方法,调用之前至少有一次next()方法的调用。
如果你想了解的更透彻,可以查看一下原码,看它是怎么实现的。
因为for each语句是由iterator语句实现的,所以如果你在循环中删除某个元素时,应该用iterator的remove()方法,可是这时你又没有iterator对象,怎么调用呢?
所以,这种情况下,一般还是用iterator来循环访问,并筛选删除。
说白了,for each就是为了让用iterator循环访问的形式看着更好看,写起来更方便。但如有删除操作,当然还是用它原来的形式了。
iterator方法是JDK提供的迭代接口进行Java集合的迭代。
Iterator iterator = list.iterator();。
while(iterator.hasNext()){。
String string = iterator.next();。
//do something。
}
迭代其实我们可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类,它是一个很典型的设计模式。Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。 在没有迭代器时我们都是这么进行处理的。如下:
对于数组我们是使用下标来进行处理的:。
int[] arrays = new int[10];。
for(int i = 0 ; i < arrays.length ; i++){。
int a = arrays[i];。
//do something。
}
对于ArrayList是这么处理的:。
List<String> list = new ArrayList<String>();。
for(int i = 0 ; i < list.size() ; i++){。
String string = list.get(i);。
//do something。
}
对于这两种方式,我们总是都事先知道集合的内部结构,访问代码和集合本身是紧密耦合的,无法将访问逻辑从集合类和客户端代码中分离出来。同时每一种集合对应一种遍历方法,客户端代码无法复用。 在实际应用中如何需要将上面将两个集合进行整合是相当麻烦的。所以为了解决以上问题,Iterator模式腾空出世,它总是用同一种逻辑来遍历集合。使得客户端自身不需要来维护集合的内部结构,所有的内部状态都由Iterator来维护。客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。
上面只是对Iterator模式进行简单的说明,下面我们看看Java中Iterator接口,看他是如何来进行实现的。
一、java.util.Iterator。
在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:
1、迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。
2、方法名称得到了改进。
其接口定义如下:
public interface Iterator {。
boolean hasNext();。
Object next();
void remove();
其中:
Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型。
boolean hasNext():判断容器内是否还有可供访问的元素。
void remove():删除迭代器刚越过的元素。
对于我们而言,我们只一般只需使用next()、hasNext()两个方法即可完成迭代。如下:
for(Iterator it = c.iterator(); it.hasNext(); ) {。
Object o = it.next();。
//do something。
前面阐述了Iterator有一个很大的优点,就是我们不必知道集合的内部结果,集合的内部结构、状态由Iterator来维持,通过统一的方法hasNext()、next()来判断、获取下一个元素,至于具体的内部实现我们就不用关心了。但是作为一个合格的程序员我们非常有必要来弄清楚Iterator的实现。下面就ArrayList的源码进行分析分析。
二、各个集合的Iterator的实现。
下面就ArrayList的Iterator实现来分析,其实如果我们理解了ArrayList、Hashset、TreeSet的数据结构,内部实现,对于他们是如何实现Iterator也会胸有成竹的。因为ArrayList的内部实现采用数组,所以我们只需要记录相应位置的索引即可,其方法的实现比较简单。
2.1、ArrayList的Iterator实现。
在ArrayList内部首先是定义一个内部类Itr,该内部类实现Iterator接口,如下:
private class Itr implements Iterator<E> {。
//do something。
而ArrayList的iterator()方法实现:
public Iterator<E> iterator() {。
return new Itr();。
}
所以通过使用ArrayList.iterator()方法返回的是Itr()内部类,所以现在我们需要关心的就是Itr()内部类的实现:
在Itr内部定义了三个int型的变量:cursor、lastRet、expectedModCount。其中cursor表示下一个元素的索引位置,lastRet表示上一个元素的索引位置。
int cursor; 。
int lastRet = -1; 。
int expectedModCount = modCount;。
从cursor、lastRet定义可以看出,lastRet一直比cursor少一所以hasNext()实现方法异常简单,只需要判断cursor和lastRet是否相等即可。
public boolean hasNext() {。
return cursor != size;。
}
对于next()实现其实也是比较简单的,只要返回cursor索引位置处的元素即可,然后修改cursor、lastRet即可,
public E next() {。
checkForComodification();。
int i = cursor; //记录索引位置。
if (i >= size) //如果获取元素大于集合元素个数,则抛出异常。
throw new NoSuchElementException();。
Object[] elementData = ArrayList.this.elementData;。
if (i >= elementData.length)。
throw new ConcurrentModificationException();。
cursor = i + 1; //cursor + 1。
return (E) elementData[lastRet = i]; //lastRet + 1 且返回cursor处元素。
}
checkForComodification()主要用来判断集合的修改次数是否合法,即用来判断遍历过程中集合是否被修改过。在java提高篇(二一)-----ArrayList中已经阐述了。modCount用于记录ArrayList集合的修改次数,初始化为0,,每当集合被修改一次(结构上面的修改,内部update不算),如add、remove等方法,modCount + 1,所以如果modCount不变,则表示集合内容没有被修改。该机制主要是用于实现ArrayList集合的快速失败机制,在Java的集合中,较大一部分集合是存在快速失败机制的,这里就不多说,后面会讲到。所以要保证在遍历过程中不出错误,我们就应该保证在遍历过程中不会对集合产生结构上的修改(当然remove方法除外),出现了异常错误,我们就应该认真检查程序是否出错而不是catch后不做处理。
final void checkForComodification() {。
if (modCount != expectedModCount)。
throw new ConcurrentModificationException();。
}
对于remove()方法的是实现,它是调用ArrayList本身的remove()方法删除lastRet位置元素,然后修改modCount即可。
public void remove() {。
if (lastRet < 0)。
throw new IllegalStateException();。
checkForComodification();。
try {。
ArrayList.this.remove(lastRet);。
cursor = lastRet;。
lastRet = -1;。
expectedModCount = modCount;。
} catch (IndexOutOfBoundsException ex) {。
throw new ConcurrentModificationException();。
}
}
这里就对ArrayList的Iterator实现讲解到这里,对于Hashset、TreeSet等集合的Iterator实现,各位如果感兴趣可以继续研究,个人认为在研究这些集合的源码之前,有必要对该集合的数据结构有清晰的认识,这样会达到事半功倍的效果!!!!
HashMap删除元素根据其遍历方式一般有两种方法,实例演示如下:
一、采用foreach模式,适用于不需要修改HashMap内元素的遍历,只需要获取元素的键/值的情况。
1、遍历如下:
2、此时删除HashMap中的元素,Java很有可能会在运行时抛出异常。
运行上面的代码,Java抛出了 java.util.ConcurrentModificationException 的异常。并附有如下信息。
可以推测,由于在遍历HashMap的元素过程中删除了当前所在元素,下一个待访问的元素的指针也由此丢失了。
二、采用迭代器遍历,不仅适用于HashMap,对其它类型的容器同样适用。
1、采用这种方法的遍历,可以用下文提及的方式安全地对HashMap内的元素进行修改,并不会对后续的删除操作造成影响。
2、运行结果没有显示,表明HashMap中的元素被正确删除了,代码如下:
扩展资料:
HashMap的遍历中删除元素的特殊情况:
如果HashMap中的键值同样是一个HashMap,假设你需要处理的是 HashMap<HashMap<String, Integer>, Double> myHashMap 时,可能需要修改myHashMap中的一个项的键值HashMap中的某些元素,之后再将其删除。
这时,单单依靠迭代器的 remove() 方法是不足以将该元素删除的。
具体代码如下:
原因在于,迭代器遍历时,每一次调用 next() 函数,至多只能对容器修改一次。上面的代码则进行了两次修改:一次添加,一次删除。
按我的想象,会用到这个方法的场景是这样的:
一个迭代器创建出来以后,也可能运行到一半的时候,有可能会有其他条件触发造成需求的变化,原有的迭代不适用了,有remove()移走其中的部分迭代对象,就不用重新建立迭代器了,执行到一半的迭代也就不需要重来了。
原文地址:http://www.qianchusai.com/java%E8%BF%AD%E4%BB%A3%E5%99%A8remove.html