Java 集合源码解析系列:
- 拆行解码 Java 集合源码之总览
- 拆行解码 Java 集合源码之 Collection 的三大体系
- 拆行解码 Java 集合源码之迭代器
- 拆行解码 Java 集合源码之 ArrayList
- 拆行解码 Java 集合源码之 LinkedList
- 拆行解码 Java 集合源码之 HashMap
- 拆行解码 Java 集合源码之 Hashtable
- 拆行解码 Java 集合源码之 LinkedHashMap
- 拆行解码 Java 集合源码之 PriorityQueue
- 拆行解码 Java 集合源码之 ArrayDeque
迭代器
还有一个接口 Iterator
,每个集合类内部通过实现该接口,实现集合元素的遍历。将遍历序列的操作与序列底层的结构分离。
该对象必须依赖于具体容器,因为每一个容器的数据结构不同;
所以迭代器对象是在容器中进行实现的(内部类)。
迭代的时候只能进行删除(可选操作)。
for(Iterator it = Collection.iterator(); it.hasNext();){
E e=it.next();
it.remove();
}
ps:1.2 之前是通过 Enumeration 接口实现遍历。
不是快速失败的!!
支持的集合较少,Hashtable 的键、值集合,Vector。
Iterator 允许遍历期间删除元素,方法命名更加友好。
foreach 与 迭代器
(1)foreach主要是针对数组或任何实现 Iterable
接口的类。
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* 返回一个可能并行的可拆分迭代器。
* 是基于原数据源(集合、数组、IO 流)的可拆分迭代器
* 虽然可以在并行流程中使用,但是并不是线程安全,尤其是拆分的过程。
* 建议在单线程的串行线程中使用,比如基于分治的任务分解过程。
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
(2)集合进行 foreach 循环时,会默认调用重写的 iterator 方法,得到实现 iterable 的迭代器对象 Iterator,从而进行遍历。(实际是一种语法糖)
for (Integer e : list) {
// do some thing
}
=>
object = list.iterator();
while (object.hasNext()) {
Integer e = object.next());
}
(3)集合可以写一个方法,返回一个实现了 Iterable 接口的 Iterator 类,进行不同方式的迭代。
注意:数组直接使用 foreach 进行遍历即可。不能够将数组转化为 Iterable 接口对象进行遍历,只能人为使用 Arrays.asList() 转化为 ArrayList 对象,然后默认调用 Iterator 方法进行遍历。
快速失败(fail fast)
集合在使用迭代器在遍历过程中,不能使用集合的 remove() 方法进行增删(修改可以),否则抛出ConcurrentModificationException。
只能使用迭代器的 remove 方法,方法内部对集合进行同步删除操作。
原理:将计数器与迭代器关联起来。在遍历每一个元素的时候都会检查一遍,返回迭代器时记录的expectedModCount 与现在容器的 ModCount 是否相等。(modCount 的含义是记录该容器被修改的次数,包括但不限于更改容器大小或其他可能干扰到迭代器的操作。)
如果使用容器的api进行操作,将无法同时更新两个变量的值,会导致失败。而迭代器的删除会同时维护索引表的内容,保证一致性。
快速失败并不是严谨保证不同步下的并发安全性,应该被用于检查bug。
**** 可拆分迭代器
public interface Spliterator<T> {
// 一个数据源的Spliterator允许有多个特征,定义的特征通过 或运算 得到一个数据源的特征 characteristics()。
/**
* 标识数据源的元素是有序的
*/
public static final int ORDERED = 0x00000010;
/**
* 标识数据源的元素是不重复的。比如基于 Set的
*/
public static final int DISTINCT = 0x00000001;
/**
* 数据源的元素是按照一定规律排序的。
* 基于该特征,要么getComparator() 有值,优先;
* 要么, 元素是实现 Comparable 接口。
*
* 同时具备 ORDERED 的特征。
* 比如基于 SortedSet。
*/
public static final int SORTED = 0x00000004;
/**
* 大小固定。
* 在遍历或拆分之前,通过 estimateSize() 得到的是数据源未修改情况下的精确计数。
* 大部分 Collection 的 Spliterator 会具备该特性。
*/
public static final int SIZED = 0x00000040;
/**
* 数据源不为空。大部分的并发集合、队列、map。
*/
public static final int NONNULL = 0x00000100;
/**
* 不可变。标识遍历期间,不可添加、删除、替换。
*/
public static final int IMMUTABLE = 0x00000400;
/**
* 并发安全。在多线程遍历的情况下,线程安全地添加、替换、删除。
* 一般不会同时存在该特征和 SIZED 或 IMMUTABLE。
*/
public static final int CONCURRENT = 0x00001000;
/**
* 通过 trySplit() 拆分出的子迭代器,同时具有 SUBSIZED 和 SIZED。
* 简单来说,所有的子迭代器,无论是直接拆分的,还是间接的,都是 SIZED。
*/
public static final int SUBSIZED = 0x00004000;
/**
* 如果存在元素,则对其执行 action;
*/
boolean tryAdvance(Consumer<? super T> action);
/**
* 对余下的元素,都执行action;直到遍历完,或遇到异常。
*/
default void forEachRemaining(Consumer<? super T> action) {
do { } while (tryAdvance(action));
}
/**
* 拆分当前 Spliterator。得到的 Spliterator 遍历的元素,将不再被当前 Spliterator 所包含。
*
* 如果当前是 ORDER 的,那么得到的 Spliterator 将会遍历一组相同特征(前缀)的元素。
*
* 除非当前是无限元素,否则最终将得到 NULL。
*
* 拆分前 estimateSize() 必定大于等于拆分后的。
* 如果是 SUBSIZED,那么拆分前的等于拆分后的总和。
*
* 此方法可能由于任何原因返回null,包括空闲,在遍历开始后无法拆分,数据结构约束和效率考虑。
*
* 注意: 理想的trySplit方法有效地(无遍历)将其元素精确地分成两半,允许平衡并行计算。
* 许多偏离这种理想仍然非常有效;例如,仅近似地拆分一个近似平衡的树,或者叶子节点可能包含一个或两个元素的树,无法进一步拆分这些节点。
* 然而,平衡的大偏差和/或过低效率的trySplit机制通常会导致较差的并行性能。
*/
Spliterator<T> trySplit();
/**
* 得到一个用于表示 forEachRemaining 还可以遍历多少的预估值。特别特别注意,不是全部,而是剩余可遍历。
* 或者如果是无限,未知,或太大难以计算,则返回 Long.MAX_VALUE
*
* 如果是 SIZED,且未拆分或未部分遍历;或SUBSIZED且未部分遍历,则返回值应该是接下来遍历的准确计数。
* 否则,此估算值可能是任意不正确的,但必须按照{@link #trySplit}调用中指定的那样减小。
*/
long estimateSize();
default long getExactSizeIfKnown() {
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}
/**
* 上述定义的枚举数值的或运算结果。
* 应该是不变的,重复调用也有相同的结果。
*
* 拆分前后可能不同。
*/
int characteristics();
default boolean hasCharacteristics(int characteristics) {
return (characteristics() & characteristics) == characteristics;
}
/**
* 如果此Spliterator的源由Comparator比较器为SORTED,则返回该Comparator。
* 如果源按Comparable自然顺序为SORTED,则返回null。否则,如果源不是SORTED,则抛出IllegalStateException。
*/
default Comparator<? super T> getComparator() {
throw new IllegalStateException();
}
/**
* A Spliterator specialized for primitive values.
*/
public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
extends Spliterator<T> {}
/**
* A Spliterator specialized for {@code int} values.
* @since 1.8
*/
public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {}
/**
* A Spliterator specialized for {@code long} values.
* @since 1.8
*/
public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {}
/**
* A Spliterator specialized for {@code double} values.
* @since 1.8
*/
public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {}
}