集合的接口与实现分离
与现代的数据结构类库的常见情况一样,Java 集合类库也将接口(interface)与实现(implementation)分离。
Collection 接口
在 Java 类库中,集合类的基本接口是 Collection
接口。除了 Map 的接口是 Map。
迭代器
集合类使用迭代器(Iterator
)来访问集合的每个元素。Iterator
接口包含 4 个方法:
public interface Iterator<E> {
E nexe();
boolean hasNext();
default void remove();
default void forEachRemaining(Consumer<? super E> action);
}
可以直接调用集合的 iterator()
来得到迭代器从而迭代集合:
Collection<String> c = ...
Iterator<String> iter = c.iterator();
while(iter.hasNext()) {
String element = iter.next();
System.out.println(element);
}
Java 封装了 for each
语句来让你更方便的迭代集合元素:
for (String element : c) {
System.out.println(element);
}
其实 Java 编译器并不知道如何遍历集合原始。上述代码能够编译通过,只是因为编译器把 for each
循环通过 Iterator
改写为了循环:
// for
for (Iterator<String> iter = c.iterator(); iter.hasNext(); ) {
String element = iter.next();
System.out.println(element);
}
// while
Iterator<String> iter = c.iterator();
while(iter.hasNext()) {
String element = iter.next();
System.out.println(element);
}
可以看到,在 Iterator
中还有一个 forEachRemaining()
,它可以和 lambda 表达式结合,遍历集合元素:
list.iterator().forEachRemaining(element -> System.out.println(element));
在 Java 中,应该理解迭代器在两个元素之间。调用 next()
,迭代器就越过下个元素,并返回越过那个元素的引用。这一点在使用 remove()
方法时应该深有体会。remove()
会删除上次调用 next()
方法时返回的元素:
Iterator<String> it = c.iterator();
it.remove(); // 不能直接调用 remove(),因为此时的 it 还未接受 next 传来的对象
Iterator<String> it = c.iterator();
it.next();
it.remove(); // OK
Iterator<String> it = c.iterator();
it.next();
it.remove();
it.remove(); // 连续调用将会抛出 IllegalStateException 异常,因为上一个 remove() 已经将 it 中 next 传来的对象移除
Iterator<String> it = c.iterator();
it.next();
it.remove(); // OK
it.next();
it.remove(); // OK
集合框架中的接口
Java集合框架为不同类型的集合定义了大量接口: