Java 基础:Iterable 和 iterator 的区别
1、Iterable 接口
Iterable 接口是 JDK 1.5 增加的接口,该接口包含三个方法:iterator()、forEach(Consumer<? super T> action) 和 spliterator(),每个方法解释都在下面的代码中。
/**
* 实现了该接口的对象能够使用 "for-each loop" 语句进行迭代遍历。
* @since 1.5
* @jls 14.14.2 The enhanced {@code for} statement
*/
public interface Iterable<T> {
/**
* 返回一个实现了迭代逻辑的迭代器对象。
*/
Iterator<T> iterator();
/**
* 迭代每一个元素,可以在自定义 action 对元素进行操作。
* @since 1.8
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* 创建一个 Spliterator。
* @since 1.8
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
Iterable 从字面上讲,它已 able
结尾,具有“使能、能够”
的含义,所以本质上它表示的是实现该接口的类对象具有可迭代性质的含义。
2、 Iterator 接口
Iterator 接口在 JDK 1.2 中就已经有了,该接口包含 4 个方法:boolean hasNext()、T next()、T remove() 和 void forEachRemaining(Consumer<? super E> action) 。
package java.util;
import java.util.function.Consumer;
/**
* 迭代器接口,用于实现迭代逻辑
* @since 1.2
*/
public interface Iterator<E> {
/**
* 用于在迭代过程中判断是否还有元素
*/
boolean hasNext();
/**
* 在迭代过程中获取下一个元素
*
* @return 下一个元素
* @throws 如果没有元素了抛出 NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* 删除这个迭代器返回的最后一个元素。
*
* @throws 如果该迭代器不支持删除元素,则抛出 UnsupportedOperationException,这也是默认实现。
* @throws 如果 next 方法还未被调用或者该方法被连续调用了两次则抛出 IllegalStateException 。
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* 遍历剩余的元素。1.8 新增方法。
*
* @throws 如果 action 参数为 null 则抛出 NullPointerException。
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
同样从字面含义上讲 Iterator 是一个名词,翻译成中文为“迭代器”,它被用于实现具体的迭代逻辑的。
3、一个简单例子:可迭代的字符的字符串
这个例子实现了可迭代字符的字符串,仅作演示用并无实际意义!
import javax.annotation.Nonnull;
import java.util.Iterator;
public class IterableString implements Iterable<Character> {
private final String str;
public IterableString(String str) {
this.str = str;
}
/**
* 创建自己实现的字符迭代器
*/
@Override
@Nonnull
public Iterator<Character> iterator() {
return new CharIterator();
}
/**
* 实现了 Iterator 接口的内部类
* 字符串字符数组迭代器实现类
*/
private class CharIterator implements Iterator<Character> {
private int pos = 0; // 字符迭代的位置
/**
* pos 小于 str.length() 说明未到字符串末尾
*/
@Override
public boolean hasNext() {
return pos < str.length();
}
/**
* 返回 pos 位置的字符,并让 pos 后移
*/
@Override
public Character next() {
return str.charAt(pos++);
}
}
}
首先让 IterableString
类实现 Iterable
接口,然后实现了一个 CharIterator
的内部类,该内部类实现了 Iterator
接口并完成可迭代字符的逻辑。
然后就可以使用 for-each 的方式遍历字符串中的字符了。
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
// 第一种:使用 Iterator 的 forEach 方法
IterableString helloWorld = new IterableString("Hello World");
helloWorld.forEach(System.out::println);
System.out.println("-----------------------------------");
// 第二种:for-each 语法糖
for (Character c : helloWorld) {
System.out.println(c);
}
System.out.println("-----------------------------------");
// 第三种:使用迭代器
Iterator<Character> iterator = helloWorld.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
其实第二种在编译后和第三种迭代器是一样的,这是 JDK 提供的语法糖而已。
4、总结
Iterator 和 Iterable 都是接口,它们两个一起配合实现数据的迭代。
- Iterable
Iterable是一个接口,用于判断一个对象是否可以被迭代。如果一个类实现了Iterable接口,那么它的对象就可以被用于for-each循环中进行遍历操作。
Iterable接口定义了一个iterator()方法,该方法用于返回一个Iterator对象,从而实现对集合的遍历。 - Iterator
Iterator 用于遍历并选择序列中的对象。它提供了一种方法来访问集合元素而不需要暴露该集合的底层表示。
Iterator对象包含了遍历集合所需的所有信息,包括当前遍历的位置以及如何通过next()方法获取下一个元素。
Iterator接口定义了hasNext()、next()和remove()三个方法,分别用于判断是否有下一个元素、获取下一个元素以及从迭代器指向的集合中删除最后一个元素。