迭代器
提供一种方法对一个容器中的各个元素进行访问,而又不暴露对象容器的内部细节。因为容器的内部结构不同,很多时候不知道该如何去遍历一个容器中的元素,为了方便操作容器内元素,提供迭代器模式。
在这之前先重温一下对于已知结构的容器的遍历方式(传统for循环)
数组使用下标
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
List使用get(角标)方法
for(int i = 0 ; i < list.size() ; i++) {
system.out.println(list.get(i));
}
那么对于其他容器Set、Map容器内没有角标,不能使用传统for循环的或者其他不知道内部结构的容器,就需要使用迭代器或者基于迭代器实现的迭代方式。
迭代接口
Iterator接口
public interface Iterator<T>{
boolean hasNext();
AnyType next();
void remove();
}
1 Java的Iterator的方法依赖当前位置,并且只能单向移动
2 使用hasNext()检查序列中是否还有下一个元素
3 使用next()方法获取序列的下一个元素
4 使用remove()方法将迭代器新进返回的元素删除
Iterable接口
public interface Iterable<T> {
Iterator<T> iterator();
}
1 Iterable接口中包含一个iterator()方法,该方法用来返回一个Iterator类型的对象(一个实现Iterator接口的对象)
2 Iterable接口被foreach用来在序列中移动,也就是说如果创建了实现Iterable接口的类,就可以将他应用在foreach语句中
3 Collection对象全部实现了Iterable接口,与foreach一起工作是Collection对象的共性
Iterable和Iterator的关系
1 首先Iterable的实现在于通过iterator方法获取一个Iterator实例
2 Iterator对象一经创建,只能单向运动,这将意味着如果在其他的位置还要遍历一遍容器则需要再创建一个Iterator对象,这也是Iterable接口做的事情,每次调用iterator()方法便返回一个新的从头开始的Iterator迭代器,各个迭代器之间互不影响。
3 两者不是只能选择一种实现的关系,而是相辅相成的,实现Iterator接口重新next()等方法对容器内部结构遍历,实现terable接口,每次调用iterator()方法都返回一个新对象。
如果我们需要为类A实现一个自定义的迭代器,首先要
a. 定义一个AIterator类实现Iterator接口,重写next()等方法
b. 在类A中实现Iterable接口,重写iterator()方法
public Iterator<T> iterator(){
return new AIterator();
}
这两者相辅相成,这也是很多地方说,Iterator是迭代类(实现一个基础的迭代类),Iterable是迭代接口的原因
我们现在知道了两个接口,一个负责底层逻辑,一个提供操作入口,不存在任何比较关系,那现在就来看看如何使用吧
1 使用iterator方法获取一个Iterator对象并返回序列的第一个元素
2 使用hasNext()检查序列中是否还有下一个元素
3 使用next()方法获取序列的下一个元素
4 使用remove()方法将迭代器新进返回的元素删除,这个删除是作用在容器自身的,会删除掉容器内的元素
这里对这些方法有一点注意的
Iterator iterator1 = list.iterator();
Iterator iterator2 = list.iterator();
//调用iterator()返回新的迭代器
List<Integer> list = Arrays.asList(new Integer[]{1,2,3,4,5});
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
if(!iterator.next().equals(5)){
System.out.println(iterator.next());
}
}
//此处输出2
//因为我们再if(!iterator.next().equals(5))以及调用了一次iteartor.next()迭代器已经前进一位
//再输出iteartor.next()又前进一位,输出2
//iterator.next()是动态的,并不是在一次遍历中就固定不动代表一个元素的
//如果需要判断输出,要拿变量存储
List<Integer> list = Arrays.asList(new Integer[]{1,2,3,4,5});
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
Integer i = (Integer) iterator.next();
if(!i.equals(5)){
System.out.println(i);
}
}
//输出1
List<Integer> list = new ArrayList<Integer>(Arrays.asList(new Integer[]{1,2,3,4,5}));
System.out.println(list);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Integer i = (Integer) iterator.next();
if(i.equals(3)){
iterator.remove();
}
}
System.out.println(list);
//输出:[1, 2, 3, 4, 5]
// [1, 2, 4, 5]
//remove方法是作用的容器本身的
如何自定义一个迭代器
1 定义一个AIterator类实现Iterator接口,重写next()等方法
private class AIterator implements Iterator<T>{
public boolean hasNest(){
xxxx;
}
public T next() {
xxx;
}
public void remove() {
xxx;
}
}
2 在类A中实现Iterable接口,重写iterator()方法
public class A implements Iterable<T> {
public Iterator<T> iterator(){
return new AIterator();
}
}
Collection集合中基于迭代器的遍历方法
Collection中通用的迭代器遍历 和 foreach
Iterator iterator = list.iterator();
while(iterator.hasNext()){
int i = (Integer) iterator.next();
System.out.println(i);
}
for (Object object : list) {
System.out.println(object);
}
集合中其他遍历方法
List
1 基于角标的get方法(不是迭代器实现的),只是在这里提醒自己一下
Set
无,就是迭代器 + foreach
Map
Map是基于键值对的,所以它的迭代器实现比较特殊
就算使用迭代器通用方法也要先通过Map.entrySet拿出所有的键值对
Map类提供了一个称为entrySet()的方法,这个方法返回一个Map.Entry实例化后的对象集,可以得到Map中所有的数据信息。
1 非entrySet,一次一次get(key)
for (Integer in : map.keySet()) { //map.keySet(); //得到所有key的集合
String str = map.get(in);//得到每个key多对用value的值
}
2 非entrySet + foreach遍历value,但是不能得到可以值
for (String v : map.values()) {//map.values(); //得到所有value的集合
System.out.println("value= " + v);
}
3 entrySet + Iterator
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
System.out.println( entry.getKey() + entry.getValue());
}
4 entrySet + foreach(推荐 尤其是数据大时)
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + entry.getValue());
}