概述
【Java】Iterable接口的使用
- 前言:遍历集合
- 写法1:for循环
- 写法2:foreach循环
- 写法3:Iterator
- Iterable
- 查看源码
- Iterable 核心方法
- 你知道 Iterable 默认指针指的的第一个对象还是指针变量呢?看完下面这个你或许就知道了
- 第二个例子代码:
- 总结
定义:为对象使用迭代器iterator提供统一调用。
接口中的函数:
获取迭代器对象:iterator();
对Iterable的每个元素执行给定操作action:forEach(Consumer<? super T> action)
在Iterable描述的元素上创建Spliterator:spliterator()
前言:遍历集合
当我们想要遍历集合时,Java为我们提供了多种选择,通常有以下三种写法:
写法1:for循环
for (int i = 0, len = strings.size(); i < len; i++) {
System.out.println(strings.get(i));
}
写法2:foreach循环
for (String var : strings) {
System.out.println(var);
}
写法3:Iterator
Iterator iterator = strings.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
那么以上三种遍历方式有何区别呢?
for循环我们很熟悉了,就是根据下标来获取元素,这个特性与数组十分吻合;
foreach则主要对类似链表的结构提供遍历支持,链表没有下标,所以使用for循环遍历会大大降低性能。
Iterator 就是我们今天要讲述的主角,它实际上就是foreach。
为什么集合可以进行foreach遍历,而我们自己定义的Java对象却不可以呢?有没有办法让任何对象都支持这种遍历方式?下面的内容会告诉我们答案。
Iterable
Iterable 是迭代器的意思,作用是为集合类提供for-each循环的支持。由于使用for循环需要通过位置获取元素,而这种获取方式仅有数组支持,其他许多数据结构,比如链表,只能通过查询获取数据,这会大大的降低效率。Iterable 是可以为不同的集合类提供遍历的最佳方式。
Iterable的文档声明仅有一句:
Implementing this interface allows an object to be the target of the “for-each loop” statement.
查看源码
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);
}
}
// 返回一个内部元素为T类型的并行迭代器
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
后两个方法是Java8后新添加的,
(1)forEach()方法:为了方便遍历并操作集合内的元素。
(2)spliterator()方法:提供了一个可以并行遍历元素的迭代器,以适应现在cpu多核时代并行遍历的需求。
其中我们可以看下default修饰符,这也是Java8后新出现的。我们知道,如果我们给一个接口新添加一个方法,那么所有他的具体子类都必须实现此方法。为了能给接口拓展新功能,而又不必每个子类都要实现此方法,因此Java8新加了default关键字,被其修饰的方法可以不必由子类实现,并且由dafault修饰的方法在接口中有方法体,这打破了Java之前对接口方法的规范。
进行迭代遍历的时候我们需要注意这种情况,就是在遍历的过程中,如果我们对元素进行添加、删除操作,那么会造成并行修改异常。对于这种情况,我们应当使用迭代器Iterator内部的 remove() 方法,而不是使用集合list直接删除元素。
自定义集合
import java.util.Iterator;
public class MyCollection<E> implements Iterable<E> {
@SuppressWarnings("unchecked")
@Override
public Iterator iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<E>{
@Override
public boolean hasNext() {
return false;
}
@Override
public E next() {
return null;
}
}
}
它的作用就是为Java对象提供foreach循环,其主要方法是返回一个Iterator
对象:
Iterator<T> iterator();
也就是说,如果想让一个Java对象支持foreach,只要实现Iterable接口,然后就可以像集合那样,通过Iterator iterator = strings.iterator()
方式,或者使用foreach,进行遍历了。
Iterable 核心方法
Iterator是foreach遍历的主体,它的代码实现如下:
// 判断一个对象集合是否还有下一个元素
boolean hasNext();
// 获取下一个元素
E next();
// 删除最后一个元素。默认是不支持的,因为在很多情况下其结果不可预测,比如数据集合在此时被修改
default void remove(){...}
// 主要将每个元素作为参数发给action来执行特定操作
default void forEachRemaining(Consumer<? super E> action){...}
Iterator
还有一个子接口,是为需要双向遍历数据时准备的,在后续分析ArrayList和LinkedList时都会看到它。它主要增加了以下几个方法:
// 是否有前一个元素
boolean hasPrevious();
// 获取前一个元素
E previous();
// 获取下一个元素的位置
int nextIndex();
// 获取前一个元素的位置
int previousIndex();
// 添加一个元素
void add(E e);
// 替换当前元素值
void set(E e);
你知道 Iterable 默认指针指的的第一个对象还是指针变量呢?看完下面这个你或许就知道了
下文内容参考自:https://blog.csdn.net/zp357252539/article/details/82757767
第一个例子代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorTest {
public static void main(String[] args){
List<String> l = new ArrayList<>();
for (int i=0;i<10;i++){
l.add(Integer.toString(i));
}
Iterator<String> i = l.iterator();
if(i.hasNext()){
i.remove();
}
for (String s : l) {
System.out.println(s);
}
}
}
运行后报如下错误
ids.autoview.tw.acconsys.test.IteratorTest
Exception in thread "main" java.lang.IllegalStateException
at java.util.ArrayList$Itr.remove(ArrayList.java:864)
at ids.autoview.tw.acconsys.test.IteratorTest.main(IteratorTest.java:17)
Process finished with exit code 1
第二个例子代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorTest {
public static void main(String[] args){
List<String> l = new ArrayList<>();
for (int i=0;i<10;i++){
l.add(Integer.toString(i));
}
Iterator<String> i = l.iterator();
i.next();
if(i.hasNext()){
i.remove();
}
for (String s : l) {
System.out.println(s);
}
}
}
运行结果:
1
2
3
4
5
6
7
8
9
Process finished with exit code 0
第一个例子和第二个例子最大的区别是,第二个例子在执行Iterator的remove方法之前,先执行了next的操作,next之前,指针指的是变量i本身,next之后才指的是第一个内容。
总结
在Java中有许多特性都是通过接口来实现的,foreach循环也是。foreach主要是解决 for 循环依赖下标的问题,为高效遍历更多的数据结构提供了支持。
参考博客:
https://www.jianshu.com/p/8c4dae2c1ae0
https://www.cnblogs.com/feiqiangsheng/p/11184196.html
最后
以上就是幸福雨为你收集整理的【Java】Iterable接口的使用的全部内容,希望文章能够帮你解决【Java】Iterable接口的使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复