一、迭代器概述
迭代器是一种设计模式,迭代器可以用于遍历集合,开发人员不必去了解这个集合的底层结构。迭代器封装了数据获取和预处理逻辑,屏蔽了容器的实现细节,无需暴露数据结构内部。在数据量非常庞大时使用迭代器进行数据迭代获取,避免全部取出占用过多的服务器资源,且可以对部分数据进行预加载,提升性能。本文将对 java 提供的 Iterator
、Iterable
和 Spliterator
三个数据迭代接口做介绍,了解其使用场景。
二、Iterator 迭代器接口
package java.util;
import java.util.function.Consumer;
public interface Iterator<E> {
// 如果迭代有更多元素,则返回true
boolean hasNext();
/**
* 返回迭代中的下一个元素
* 如果没有元素则抛出NoSuchElementException异常
*/
E next();
/**
* 从底层集合中移除此迭代器已经返回的最后一个元素,只能在next被调用后使用
* UnsupportedOperationException – 迭代器不支持remove操作
* IllegalStateException – 没有调用next方法或者已经执行过remove
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
// 对每个剩余元素执行给定的操作,直到处理完所有元素或操作引发异常。
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
示例
MyIterator
是一个简单的迭代器示例,实现了 hasNext
和 next
两个方法,对 list
数组的取值逻辑进行了封装。如果数据取值非常耗时,可以非常方便的在 hasNext
进行下一列数据的预加载,能够提升性能。
class MyIterator<T> implements Iterator<T> {
private T[] list;
private int i;
public MyIterator(T[] list) {
this.list = list;
}
@Override
public boolean hasNext() {
return i < list.length;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return list[i++];
}
}
public class IteratorTest {
public static void main(String[] args) {
String[] list = new String[10];
for (int i = 0; i < list.length; i++) {
list[i] = String.valueOf(i);
}
MyIterator myIterator = new MyIterator(list);
while (myIterator.hasNext()) {
System.out.println(myIterator.next());
}
}
}
三、Iterable 迭代器接口
实现 Iterable
接口支持在增强 for
循环中进行迭代。
增强 for
中先调用 Iterable.iterator()
方法获取一个迭代器,获取到迭代器后,调用 Iterator.hasNext()
方法判断是否有后继数据,如果有后继数据,则调用 Iterator.next()
方法取得数据。
package java.lang;
import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
public interface Iterable<T> {
/**
* 返回T类型元素的迭代器
*/
Iterator<T> iterator();
/**
* 对Iterable每个元素执行给定的操作,直到处理完所有元素或操作引发异常
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* 在此Iterable描述的元素上创建一个Spliterator
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
示例
MyIterator
为上述 Iterator
示例的自定义迭代器。
class MyIterable<T> implements Iterable<T> {
private T[] list;
public MyIterable(T[] list) {
this.list = list;
}
@Override
public Iterator<T> iterator() {
return new MyIterator<>(list);
}
}
public class IteratorTest {
public static void main(String[] args) {
String[] list = new String[10];
for (int i = 0; i < list.length; i++) {
list[i] = String.valueOf(i);
}
Iterable<String> iterable = new MyIterable<>(list);
for (String item : iterable) {
System.out.println(item);
}
for (String item : iterable) {
System.out.println(item);
}
}
}
四、Spliterator 分片迭代器接口
Spliterator
是在 JDK 1.8 中新增的迭代器,为了对并发提供支持,能够对迭代数据进行拆分、分片进行迭代。
package java.util;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
public interface Spliterator<T> {
/**
* 如果存在剩余元素,则对其执行给定的操作,返回true;否则返回false。
* 如果此Spliterator是ORDERED则按遇到顺序执行操作,动作抛出的异常被转发给调用者
*/
boolean tryAdvance(Consumer<? super T> action);
/**
* 在当前线程中按顺序为每个剩余元素执行给定的操作,直到处理完所有元素或操作引发异常。
* 如果此Spliterator是ORDERED则按遇到顺序执行操作,动作抛出的异常被转发给调用者
*/
default void forEachRemaining(Consumer<? super T> action) {
do { } while (tryAdvance(action));
}
/**
* 如果此 spliterator 可以分区,则返回一个Spliterator覆盖元素,从该方法返回时,该元素不会被此Spliterator覆盖。
* 如果此 Spliterator 是ORDERED ,则返回的 Spliterator 必须涵盖元素的严格前缀。
* 除非此 Spliterator 覆盖无限数量的元素,否则对trySplit()重复调用最终必须返回null 。 非空返回时:
* 拆分前为estimateSize()报告的值,拆分后必须大于或等于estimateSize()和返回的Spliterator; 和
* 如果这是Spliterator SUBSIZED ,然后estimateSize()此spliterator分裂之前必须等于总和estimateSize()
* 这和分割后的返回Spliterator。
* 此方法可能出于任何原因返回null ,包括空性、遍历开始后无法拆分、数据结构约束和效率考虑
*/
Spliterator<T> trySplit();
/**
* 返回对forEachRemaining遍历将遇到的元素数量的估计,如果无限、未知或计算成本太高,则返回
* Long.MAX_VALUE 。
* 如果此Spliterator为SIZED且尚未部分遍历或拆分,或者此Spliterator为SUBSIZED且尚未部
* 分遍历,则此估计必须是完整遍历将遇到的元素的准确计数。否则,此估计可能会任意地不准确,但必
* 须按照trySplit调用之间的指定减少。
*/
long estimateSize();
/**
* 如果此 Spliterator 为SIZED则返回estimateSize()便捷方法,否则返回-1
*/
default long getExactSizeIfKnown() {
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}
/**
* 返回此Spliterator及其元素的特征值。 结果被表示为ORDERED、DISTINCT、SORTED
* 、SIZED、NONNULL、IMMUTABLE、CONCURRENT、SUBSIZED的或运算值
*/
int characteristics();
/**
* 如果具有当前特征值返回true
*/
default boolean hasCharacteristics(int characteristics) {
return (characteristics() & characteristics) == characteristics;
}
/**
* Spliterator包含特征值SORTED时,list是通过Comparator排序的,则返回
* Comparator,如果Spliterator的list是自然排序的 ,则返回null
* 特征值不是SORTED下抛错
*/
default Comparator<? super T> getComparator() {
throw new IllegalStateException();
}
/**
* 元素定义了遇到顺序
*/
public static final int ORDERED = 0x00000010;
/**
* 对于每对遇到的元素x, y是不同的, 即!x.equals(y)
*/
public static final int DISTINCT = 0x00000001;
/**
* 遇到顺序遵循定义的排序顺序
*/
public static final int SORTED = 0x00000004;
/**
* 在遍历或拆分之前从estimateSize()返回的值表示有限大小,在没有结构源
* 修改的情况下,表示完整遍历将遇到的元素数量的精确计数
*/
public static final int SIZED = 0x00000040;
/**
* 遇到的元素不会为null
*/
public static final int NONNULL = 0x00000100;
/**
* 元素源不能在结构上进行修改; 即不能添加、替换或删除元素,因此在遍历过程
* 中不会发生这种变化
*/
public static final int IMMUTABLE = 0x00000400;
/**
* 元素源可以在没有外部同步的情况下由多个线程安全地同时修改(允许添加、替换
* 和/或删除)。 如果是这样,Spliterator 应该有一个关于遍历期间修改影响
* 的文件化策略。
*/
public static final int CONCURRENT = 0x00001000;
/**
* 由trySplit()产生的所有Spliterator都将是SIZED和SUBSIZED。
*/
public static final int SUBSIZED = 0x00004000;
/**
* 专门用于原始值的Spliterator
*/
public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
extends Spliterator<T> {
@Override
T_SPLITR trySplit();
@SuppressWarnings("overloads")
boolean tryAdvance(T_CONS action);
@SuppressWarnings("overloads")
default void forEachRemaining(T_CONS action) {
do { } while (tryAdvance(action));
}
}
/**
* 专门用于int值的Spliterator
*/
public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
@Override
OfInt trySplit();
@Override
boolean tryAdvance(IntConsumer action);
@Override
default void forEachRemaining(IntConsumer action) {
do { } while (tryAdvance(action));
}
@Override
default boolean tryAdvance(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
return tryAdvance((IntConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
return tryAdvance((IntConsumer) action::accept);
}
}
@Override
default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
forEachRemaining((IntConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
forEachRemaining((IntConsumer) action::accept);
}
}
}
/**
* 专门用于long值的Spliterator
*/
public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
@Override
OfLong trySplit();
@Override
boolean tryAdvance(LongConsumer action);
@Override
default void forEachRemaining(LongConsumer action) {
do { } while (tryAdvance(action));
}
@Override
default boolean tryAdvance(Consumer<? super Long> action) {
if (action instanceof LongConsumer) {
return tryAdvance((LongConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)");
return tryAdvance((LongConsumer) action::accept);
}
}
@Override
default void forEachRemaining(Consumer<? super Long> action) {
if (action instanceof LongConsumer) {
forEachRemaining((LongConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)");
forEachRemaining((LongConsumer) action::accept);
}
}
}
/**
* 专门用于double值的Spliterator
*/
public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
@Override
OfDouble trySplit();
@Override
boolean tryAdvance(DoubleConsumer action);
@Override
default void forEachRemaining(DoubleConsumer action) {
do { } while (tryAdvance(action));
}
@Override
default boolean tryAdvance(Consumer<? super Double> action) {
if (action instanceof DoubleConsumer) {
return tryAdvance((DoubleConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)");
return tryAdvance((DoubleConsumer) action::accept);
}
}
@Override
default void forEachRemaining(Consumer<? super Double> action) {
if (action instanceof DoubleConsumer) {
forEachRemaining((DoubleConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)");
forEachRemaining((DoubleConsumer) action::accept);
}
}
}
}
示例
class MySpliterator<T> implements Spliterator<T> {
private T[] list;
private int index; // 开始位置
private int fence; // 结束位置
public MySpliterator(T[] list, int index, int fence) {
this.list = list;
this.index = index;
this.fence = fence;
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (index >= fence) {
return false;
}
action.accept(list[index++]);
return index < fence;
}
@Override
public Spliterator<T> trySplit() {
int i = index;
if (fence - i < 2) {
return null;
}
int j = (index + fence)/2;
index = j;
return new MySpliterator<>(list, i, j);
}
@Override
public long estimateSize() {
return fence - index;
}
@Override
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}
public class IteratorTest {
public static void main(String[] args) {
String[] list = new String[10];
for (int i = 0; i < list.length; i++) {
list[i] = String.valueOf(i);
}
Spliterator<String> spliterator = new MySpliterator<>(list, 0, list.length);
Spliterator<String> spliterator2 = spliterator.trySplit();
new Thread(()-> spliterator.forEachRemaining(n-> System.out.println("Thread-1 = " + n))).start();
new Thread(()-> spliterator2.forEachRemaining(n-> System.out.println("Thread-2 = " + n))).start();
}
}