概念:迭代器(iterator)是一种对象,只要拿到这个对象,使用迭代器就可以遍历这个对象的内部,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。
java中常用的迭代方式
1、Iterator
(1)、Java中的Iterator功能比较简单,并且只能单向移动,
使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
Package java.util;
public interface Iterator<E> {
boolean hasNext();//使用hasNext()检查序列中是否还有元素。
E next();//使用next()获得序列中的下一个元素
void remove();//使用remove()将迭代器新返回的元素删除
}
(2)、讲到迭代器的时候就顺便把Iterable这个接口也做一下说明。
Iterable接口中只有一个iterator()方法,也就是返回一个迭代器。
import java.util.Iterator;
public interface Iterable<T> {
Iterator<T> iterator();//返回一个迭代器
}
(3)、其实大多数时候我们是用不到Iterable的,但是如果我们查看一下Collection接口,会发现它是实现了Iterable接口的。
(4)、我们常用的实现了该接口的类有: Collection, Deque, List, Queue, Set等。实现这个接口允许对象成为 Foreach 语句的目标。也就是说只有实现该接口,才可以通过Foreach语法遍历你的底层序列。如果我们自定义一个类实现了Iterable接口,那么它就可以用于foreach语句中。
(5)、下面写一个Iterator的基本例子
public class ArrayListDemo {
public static void main(String[] args) {
//list对象
List<String> listStrs = new ArrayList<String>();
listStrs.add("java");
listStrs.add("c");
listStrs.add("jquery");
//List接口实现了Iterable接口
Iterator<String> iterList= listStrs.iterator();
while(iterList.hasNext()){
System.out.println(iterList.next());
}
//Set对象
Set<String> setStrs = new HashSet<String>();
setStrs.add("wang");
setStrs.add("zhang");
setStrs.add("deng");
//Set接口实现了Iterable接口
Iterator<String> iterSet= setStrs.iterator();
while(iterSet.hasNext()){
System.out.println(iterSet.next());
}
//Map对象
Map<String, String> mapStrs = new HashMap<String, String>();
mapStrs.put("1", "student");
mapStrs.put("2", "teacher");
//Map对象没有实现Iterable接口,但是mapStrs.entrySet()返回的是一个set
Iterator<Entry<String, String>> iterMap = mapStrs.entrySet().iterator();
while(iterMap.hasNext()){
Entry<String, String> strMap=(Entry<String, String>)iterMap.next();
System.out.println(strMap.getValue());
}
}
}
当然,如果我们想双向移动,也就是可以从头和尾进行遍历,我们可以用针对不同接口的迭代器,例如针对list的迭代器ListIterator,该迭代器只能用于各种List类的访问。
2、foreach
(1)、foreach是jdk1.5新增的loop方法,可以用来遍历集合而不用知道集合的大小,格式如下:
for(variable var :collection){ statement; }
(2)、写一个基本例子:
public class ForEachDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<String> ();
for(String str:list){
System.out.println(str);
}
}
}
使用foreach的优势就是结构简单,不用关心容器的大小,直接遍历即可。
3、for循环
这种方式是最原始的的遍历容器的方式,缺点是遍历的时候需要知道容器的大小。
4、Iterator和for循环的比较
其实这个问题是要看需要遍历的容器决定的,不能直接拿来做比较,假如要比较的容器是list的实现类,ArrayList和LinkedList。
(1)、首先ArrayList内部是一种动态数组的数据结构,get(0)和get(1)这两个元素在物理上位置上也是相连的,随机获取元素的时间复杂度是o(1)。
(2)、LinkedList内部是一种链表的数据结构,随机获取元素的时间复杂度是o(n)。
(3)、因为在for循环中调用list.get(i)获取元素是一种随机访问,所以这个时候ArrayList效率要高很多,特别是当数量级特别大的时候。
(4)、在Iterator中next()方法,采用的即是顺序访问的方法,因此LinkedList中使用Iterator比较快。
使用for循环的方式如下:
public static void main(String[] args) {
// add elements
int size = 2000000;
List<String> list = new LinkedList<String>();
for (int i = 0; i < size; i++) {
list.add("Just some test data");
}
long startTime = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
list.get(i);
if (i % 10000 == 0) {
System.out.println("query 10000 elements spend: "
+ (System.currentTimeMillis() - startTime));
startTime = System.currentTimeMillis();
}
}
}
如果换成Iterator:
public static void main(String[] args) {
// add elements
int size = 2000000;
List<String> list = new LinkedList<String>();
for (int i = 0; i < size; i++) {
list.add("Just some test data");
}
long startTime = System.currentTimeMillis();
Iterator<String> it = list.iterator();
int i = 0;
while (it.hasNext()) {
it.next();
++i;
if (i % 10000 == 0) {
System.out.println("query 10000 elements spend: "
+ (System.currentTimeMillis() - startTime));
startTime = System.currentTimeMillis();
}
}
}