我是靠谱客的博主 幸福雨,最近开发中收集的这篇文章主要介绍【Java】Iterable接口的使用,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

【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接口的使用所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部