Collection接口的子类由于覆写了toString()方法,所以直接打印就可以进行内容的输出,但是,这并不是它们的标准输出方式。JDK提供了四中输出集合的方式,分别是:
- Iterator
- ListIterator
- Enumeration
- foreach
1. Iterator迭代器输出
在JDK1.5之前,Collection接口中定义有iterator()方法,通过此方法可以取得Iterator接口的实例化对象。通过该实例化对象进行迭代器输出。
而在JDK1.5之后,Collection接口继承Iterable接口,iterator()方法是该接口中的方法,该方法实质上还是返回一个Iterator接口的实例化对象,只是继承结构发生了改变,如下:
// 继承 Iterable 接口
public interface Collection<E> extends Iterable<E>
// 接口中还有其他的方法
public interface Iterable<T> {
// 返回一个Iterator对象的实例
Iterator<T> iterator();
}
因为List接口和Set接口继承与Collection接口,所以它俩的子类也有这个方法。
Iterator也是一个接口,在不同的类中,会自己实现接口中的方法。
接口中主要方法如下:
public interface Iterator<E> {
// 是否存在下一个元素
boolean hasNext();
// 取得下一个元素
E next();
// 删除当前元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
注意:这里的”下一个元素”是以没有得到元素的时刻为时间参考点,实际上的意思就是获取当前元素。比较绕,大家一定要理解。
使用如下:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
public static void main(String[] args) {
// Iterator()迭代输出,适用于Collection所有实现类
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
// 实例化iterator对象
Iterator<Integer> iterator = list.iterator();
// iterator使用格式,先判断是否存在元素,再获取该元素
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
运行结果:
关于迭代器还有一点要讲。在迭代器遍历集合的过程中,绝对不能对集合元素进行改变,否则会抛出 ConcurrentModificationException 异常。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
// 实例化iterator对象
Iterator<Integer> iterator = list.iterator();
// iterator使用格式
while(iterator.hasNext()) {
int remove = iterator.next();
// 使用ArrayList的remove()方法
list.remove(remove);
}
}
}
抛出异常:
Collection接口实现类的remove,add等操作会改变modCount(版本号,了解即可)。
在iterator遍历期间,如果发现modCount与开始遍历时不一样,就会抛出 ConcurrentModificationException异常。
而Iterator接口提供的remove不会修改modCount,所以非要修改的话,可以使用这个方法。
2. ListIterator双向迭代器
Iterator迭代器只能从前向后将内容输出,而List接口扩充的ListIterator却可以从前向后,也可以从后向前。
// 取得ListIterator对象
public ListIterator listIterator();
双向迭代器使用方法和迭代器一致,也是一个接口,其中的方法如下:
public interface ListIterator<E> extends Iterator<E> {
// 是否含有下一个元素
boolean hasNext();
// 取得下一个元素
E next();
// 是否含有上一个元素
boolean hasPrevious();
// 取得上一个元素
E previous();
}
看下面的例子:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Test {
public static void main(String[] args) {
// 双向迭代器ListIterator
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
// 实例化ListIterator对象
ListIterator<Integer> listIterator = list.listIterator();
// 从前到后输出
System.out.println("从前向后依次输出:");
while(listIterator.hasNext()) {
System.out.println(listIterator.next());
}
// 从后向前输出
System.out.println("从后向前依次输出:");
while(listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
}
}
运行结果:
如果要想实现由后向前的输出,那么应该首先进行从前向后的输出,否则无法实现双向。
3. Enumeration枚举输出
枚举输出是Vector子类所独有的,其它的子类都没有这种输出形式。Enumeration最早的设计就是为Vector服务的,在Vector类中提供有一个取得Enumeration接口对象的方法:
public Enumeration elements()
Enumeration接口主要方法如下:
// 判断是否有下一个元素
public boolean hasMoreElements();
// 取得元素
public E nextElement();
使用如下:
import java.util.Enumeration;
import java.util.Vector;
public class Test {
public static void main(String[] args) {
// Enumeration枚举输出
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(3);
vector.add(5);
vector.add(7);
// 获取Enumeration对象
Enumeration<Integer> enumeration = vector.elements();
while(enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
}
}
运行结果:
4. foreach输出
从JDK1.5开始foreach可以输出数组(包含List),实际上除了数组之外也可以输出集合(Set)。
使用如下:
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
// foreach输出,适用于Collection所有实现类
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(3);
set.add(5);
set.add(7);
for(Integer tmp : set) {
System.out.println(tmp);
}
}
}
运行结果:
这就是Collection的四种输出格式,推荐大家使用迭代器进行输出,因为该方法效率高,安全性好。