迭代器是一种重要的设计模式,Java语言已经内置实现了。和迭代器相关的两个重要接口是Iterable
和iterator
。
集合类应该实现Iterable
,它只有一个方法Iterator<T> iterator()
,也就是返回一个实现了iterator
的对象,这个对象就是真正的迭代器对象,我们使用它迭代我们的集合类。
迭代器接口Iterator
有三个主要方法:
boolean hasNext()
返回迭代的下一个对象是否存在E next()
返回迭代的下一个对象void remove()
从集合中删除当前迭代的对象ArrayList
实现了List
接口,List
继承了Collection
接口,Collection
接口继承了Iterable
接口。因此我们可以使用迭代器遍历ArrayList
。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main
{
public static void main(String[] args)
{
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
Iterator<Integer> integerIterator = integerList.iterator();
while(integerIterator.hasNext())
{
System.out.println(integerIterator.next());
}
}
}
Java引入了foreach语法,简化了迭代器的使用。实际上,使用foreach也是迭代器在起作用。
使用foreach遍历ArrayList:
public class Main
{
public static void main(String[] args)
{
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
for(Integer integer : integerList)
{
System.out.println(integer);
}
}
}
有时我们需要让自己设计的类能够迭代,Java中我们不需要再“发明”一个迭代器模式,因为Java语言已经为我们提供了这样的两个接口。下面例子编写了一个我们自己的泛型可迭代对象,并使用foreach语法进行遍历:
MyCollection.java
import java.util.Iterator;
class MyCollection<T> implements Iterable<T>
{
private T[] array;
private int size;
public MyCollection(T[] array)
{
this.array = array;
this.size = array.length;
}
@Override
public Iterator<T> iterator()
{
return new Iterator<T>()
{
private int index = 0;
@Override
public boolean hasNext()
{
return index < size;
}
@Override
public T next()
{
return array[index++];
}
};
}
}
Main.java
public class Main
{
public static void main(String[] args)
{
Integer[] intArr = {1, 2, 3};
MyCollection<Integer> intCollection = new MyCollection<>(intArr);
for(Integer integer : intCollection)
{
System.out.println(integer);
}
}
}
MyCollection
实现了Iterable
接口,iterator()
方法中,使用匿名类创建一个Iterator
迭代器对象并返回。迭代器对象中包含了hasNext()
和next()
的实现。由于我们的MyCollection
实现了Iterable
,因此Main
中可以使用foreach对其进行迭代。
Java8引入了lambda表达式,并向Iterable
添加了一个方法void forEach(Consumer<? super T> action)
,这是一个函数式接口,我们可以创建匿名类实现Consumer
,但这样写太繁琐了,下面演示结合lambda表达式的foreach简化写法:
public class Main
{
public static void main(String[] args)
{
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
integerList.forEach((i)-> System.out.println(i));
}
}
上面代码中,i
是正在迭代的变量,我们省略了其类型,因为lambda表达式会进行类型推断。实际上,我们还能把上面的代码进一步简化成方法引用:integerList.forEach(System.out::println);
,不过我一直不是很习惯这种写法,还是觉得上一种写法比较优美。