概述
java.lang.Iterable
接口是java集合的顶级接口之一,因为接口Collection继承了该接口,使得所有实现Collection的集合类都间接实现了Iterable接口。在JavaDoc中是这样定义Iterable接口的作用:
// Implementing this interface allows an object to be the target of the "for-each loop" statement.
复制代码
也就是,实现Iterable接口后,对象便可以使用for-each
循环了。在JDK8之前,Iterable接口只有一个方法:iterator()
。在JDK8时,新加了forEach
和spliterator
两个方法。
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
复制代码
方法
iterator()方法
通过这个方法返回一个Iterator接口的实现,以遍历集合的元素。Iterator
接口的讨论在本人的另一篇文章中已经介绍了:传送门
forEach(Consumer<? super T>)方法
forEach方法是JDK8中新增的一个default方法,官方的文档:
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
复制代码
大概的意思是:
- forEach方法接受一个Consumer的消费行为;
- 将集合中的每个元素作为消费行为的
accept
方法的参数执行,直到每个元素都处理完毕或者抛出异常; - 除非指定了消费行为
action
的实现,否则默认情况下是按元素顺序依次迭代。
举个栗子,说明一下JDK8前后迭代元素的方法:
package me.ifight.controller;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
/**
* @description: 测试
* @author: tjliu
* @create: 2019-01-15 22:45
**/
public class testController {
public static void main(String[] args) {
List<String> xxBrothers = new ArrayList<>();
xxBrothers.add("王宝强");
xxBrothers.add("陈羽凡");
xxBrothers.add("贾乃亮");
String brother = null;
System.out.println("JDK5 start...");
Iterator<String> it = xxBrothers.iterator();
while (it.hasNext()) {
brother = it.next(); // 经典遍历方式
System.out.println("next brother: " + brother);
}
System.out.println("JDK5 end...\n");
System.out.println("JDK8 start...");
xxBrothers.forEach(s -> {
System.out.println("forEach brother: " + s); // 大热的forEach遍历
});
System.out.println("JDK8 end...\n");
System.out.println("JDK8,使用自定义的消费动作行为,start...");
MyConsumer myConsumer = new MyConsumer();
xxBrothers.forEach(myConsumer); // 自定义遍历行为
System.out.println("JDK8,使用自定义的消费动作行为,end...");
}
// 自定义消费行为动作Consumer action
static class MyConsumer implements Consumer<Object> {
@Override
public void accept(Object t) {
String newStr = "兄弟" + (String) t;
System.out.println("consumer: " + newStr);
}
}
}
-----------------output----------------
JDK5 start...
next brother: 王宝强
next brother: 陈羽凡
next brother: 贾乃亮
JDK5 end...
JDK8 start...
forEach brother: 王宝强
forEach brother: 陈羽凡
forEach brother: 贾乃亮
JDK8 end...
JDK8,使用自定义的消费动作行为,start...
consumer: 兄弟王宝强
consumer: 兄弟陈羽凡
consumer: 兄弟贾乃亮
JDK8,使用自定义的消费动作行为,end...
复制代码
spliterator()方法
Spliterator
(splitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历。
Q&A
Iterable
接口和Iterator
接口的区别?
- Iterator把一个集合的实现和遍历进行了分离,使用Iterator对象可以不用关心具体的集合对象的具体类型和内部实现。
- 而Iterable接口是为了实现
for-each
循环设计的,Iterable的接口表示直接返回了Iterator对象,最终还是使用Iterator来进行集合的遍历工作。
- 为什么不把Iterator和Iterable两个接口合并,直接在Iterable里面定义
hasNext()
,next()
等方法呢。或者为什么Collection接口不直接继承Iterator,放弃Iterable接口? 原因有两点:
- Iterator接口的核心方法
next()
或者hasNext()
是依赖于迭代器的当前迭代位置的,如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代的位置信息。当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()
方法的结果会变成不可预知。除非再为Iterator接口添加一个reset()
方法,用来重置当前迭代位置。但即时这样,Collection也只能同时存在一个当前迭代位置。而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。多个迭代器是互不干扰的。 - 实现了
Iterable
的类可以实现多个Iterator内部类,例如LinkedList中的ListItr
和DescendingIterator
两个内部类,就分别实现了双向遍历和逆序遍历。通过返回不同的Iterator实现不同的遍历方式,这样更加灵活。如果把两个接口合并,就没法返回不同的Iterator实现类了。示例代码:
import java.util.*;
public class MutilIterator implements Iterable<String> {
private String[] words = "May I get offers this summer.".split(" ");
//默认的迭代器,前向遍历
public Iterator<String> iterator() {
//匿名内部类
return new Iterator<String>() {
private int index = 0;
public boolean hasNext() {return index < words.length;}
public String next() { return words[index++]; }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
//反向迭代器
public Iterable<String> reverseIterator() {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int index = words.length - 1;
public boolean hasNext() {return index > -1; }
public String next() {return words[index--]; }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
};
}
//随机迭代器,注意这里不是创建一个新的Iterator,而是返回了一个打乱的List中的迭代器
public Iterable<String> randomized() {
return new Iterable<String>() {
public Iterator<String> iterator() {
List<String> shuffled = new ArrayList<>(Arrays.asList(words));
Collections.shuffle(shuffled, new Random(47));
return shuffled.iterator();
}
};
}
public static void main(String[] args) {
MutilIterator mi = new MutilIterator();
//默认的迭代器
for (String String : mi) {
System.out.print(String + " ");
}
System.out.println();
//反向迭代器
for (String String : mi.reverseIterator()) {
System.out.print(String + " ");
}
System.out.println();
//随机迭代器
for (String String : mi.randomized()) {
System.out.print(String + " ");
}
}
}
-----------------output---------------
May I get offers this summer.
summer. this offers get I May
I this offers summer. May get
复制代码