1、迭代器的感性认识
对于Collection类下的集合如各种List各种Set,用于实现这些集合的数据结构各不相同,比如数组实现的ArrayList、链表实现的LinkedList,当客户端知道要使用的集合的底层结构的时候可以选择相应的遍历方式。
比如客户端知道ArrayList是用数组实现的,可以使用遍历数组的方式遍历ArrayList。如果客户端需要遍历的容器类型发生了变换可能就不能或者不适合使用先前的遍历方式,比如如果把ArrayList换成LinkedList,虽然仍然可以使用这种方式遍历但性能大大降低;如果换成某个set,甚至不能使用这种方式遍历。
ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); }
为了提高代码的通用性减小耦合性,在客户端和容器之间新增了一个新的角色:迭代器,迭代器负责屏蔽了各种Collection实现类的区别,采用同样的迭代器语法可以遍历Collection的所有子类,这样以来客户端的代码无需关心集合类的具体实现。
Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } Iterator<Integer> linkIterator = list2.iterator(); while (linkIterator.hasNext()){ System.out.println(linkIterator.next()); } Iterator<Integer> setIterator = set.iterator(); while (setIterator.hasNext()){ System.out.println(setIterator.next()); }
迭代器往小了说是一种遍历集合的方式,往大了说他也是一种设计模式。
2、源码
可以猜出迭代器应该是某种接口,而且是应该靠近Collection继承体系顶层的接口,因为Collection集合下的所有类是通用的。
public interface Iterable<T> { Iterator<T> iterator();
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } }
iterable接口中第一个方法用来返回iterator对象,二者的名字很像。从英语语法的角度分析iterable是一个形容词代表实现了该接口的对象有可迭代的能力,iterator是一个名词是具体迭代的执行者又称迭代器。实现了iterable接口的集合对象通过返回的iterator实现了对该集合的迭代。剩下两个方法的jdk-1.8中新增的,它们使用default关键字修饰。default关键字允许在接口中定义方法,且不要求实现了该接口的类实现该方法。
package java.util; import java.util.function.Consumer; /** public interface Iterator<E> { boolean hasNext();
E next();
default void remove() { throw new UnsupportedOperationException("remove"); } default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
关注的重点是iterator方法,hasNext方法用于判断集合中是否存在下一个元素,next用于取出下一个元素;剩下的两个default修饰的方法是jdk-1.8新增的。