Java迭代器详解,看这一篇就够了

🚩Java 迭代器详解

📚迭代器的定义

迭代器是属于设计模式之一,迭代器模式提供了一种方法来顺序访问一个聚合对象中各个元素,而不保留该对象的内部表示。

1)Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器
3)Iterator仅用于遍历集合,Iterator本身并不存放对象。

📒认识Iterator

✏️类结构图

在这里插入图片描述
通过观察类结构图的继承关系我们发现,集合的顶层接口Collection继承Iterable接口。

✒️Iterable接口

public interface Iterable<T> {
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}

Iterable接口中有一个Iterator方法,它返回一个Itertator对象

🖍️Iterator接口

public interface Iterator<E> {
    boolean hasNext();
    
    E next();
    
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
}
📃Iterator接口的方法
返回值类型方法名功能
booleanhasNext()判断集合是否还有元素,如果返回 true 表示集合还有元素,返回 false 表示集合中没有元素;一般对集合的访问通过 while(hasNext()) 判断是否还需要遍历。
E next()获取集合中遍历的当前元素 ;一般先调用 hasNext() 方法判断是否存在元素,再调用 next() 获取元素,需要进行循环交替遍历集合中的元素。
voidremove删除集合中的元素。

📙迭代器的使用

🏷️使用迭代器遍历集合

我们用ArrayList集合存放一些整型数据做示例,然后将其集合中的元素一一遍历打印输出。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class TestDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        list.add(333);

        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()) {
            int value = iterator.next();
            System.out.print(value + " ");
        }
    }
}

运行结果:
在这里插入图片描述
观察运行结果我们发现,通过迭代器我们将ArrayList集合中的元素一一打印了出来。

🔖Itertor的执行原理

在上述的示例中,迭代器是如何实现对集合的遍历呢?

⏳图示执行过程

在这里插入图片描述

⌛执行过程详解

①首先得到一个集合的迭代器Iterator iterator = list.iterator();
②进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置的元素111返回。
③再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置222的元素返回。
④再次进入while循环,调用hasNext()判断是否有下一个元素,返回true,Iterator.next()移动一个位置,将该位置333的元素返回。
⑤再次进入while循环,调用hasNext()判断是否有下一个元素,返回false,循环结束。


迭代器的遍历过程中先通过hastNext()方法判断是否有下一个元素,如果存在下一个元素再调用next()方法获取元素,在这里next()方法先往后移动一个元素位置,再返回该位置的元素。因此,在调用next()方法之前必须要调用hastNext()方法进行检测;如果没有调用并且没有下一个元素,直接调用next()方法会抛出 NoSuchElementException异常

🃏生成迭代器的快捷键

一开始使用迭代器可能会觉得麻烦,但是如果用的Idea编译器是有快捷键的,输入itit再回车就会直接生成。
在这里插入图片描述

📕迭代器中的remove()

⛄迭代器的remove()方法使用

Iterator接口中除了hasNext()next()方法外,还有一个remove()方法,即删除集合中的元素

如删除上述示例集合中的元素111

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"all"})
public class TestDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        list.add(333);

        System.out.println("删除前:" + list);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer value =  iterator.next();
            if(value == 111) iterator.remove();
        }
        System.out.println("删除后" + list);
    }
}

运行结果:
在这里插入图片描述

☃️迭代器遍历中调用集合revome()方法触发异常

在Java集合中,以集合ArrayList为例,在使用中可能会遇到删除的需求场景,此时如果代码书写不当,极有可能会抛出java.util.ConcurrentModificationException异常信息。
在上述示例中用Iterator调用了迭代器remove()方法,如果在使用中不小心调用了集合中的remove()方法会发生什么?

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"all"})
public class TestDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        list.add(333);

        System.out.println("删除前:" + list);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer value =  iterator.next();
            if(value == 111) list.remove(Integer.valueOf(111));
        }
        System.out.println("删除后" + list);
    }
}

运行结果:
在这里插入图片描述
运行结果中抛出java.util.ConcurrentModificationException异常信息。这是因为触发了集合中并发修改的异常 接下来我们通过源码对抛出异常的原因进行剖析。

    public Iterator<E> iterator() {
        return new Itr();
    }

ArrayList集合的Iterator方法中,是通过返回Itr对象来获得迭代器的。ItrArrayList的一个内部类,它实现了Iterator接口,代码如下:

   private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

Itr类属性

属性含义
cursor索引下标,表示下一个可以访问的元素的索引,默认值为 0
lastRet索引下标,表示上一个元素的索引,默认值为 -1
expectedModCount对集合修改的版本号,初始值为ModCount

ModCount定义在AbstractList接口中,初始值为0,定义如下:

 protected transient int modCount = 0;

ModCount是版本号,在对集合进行变更操作(增加、删除、修改等)的时候会对版本号进行 +1 操作。


结合上述代码进行抛出java.util.ConcurrentModificationException异常的解释。
①初始化ArrayList,添加三次元素,即三次调用add()方法,进行三次modCount++; 此时, m o d C o u n t = 3 , s i z e = 3 ; \color{red}{modCount = 3,size = 3;} modCount=3size=3
②初始化Iterator迭代器进行循环,此时, e x p e c t e d M o d C o u n t = m o d C o u n t = 3 , \color{red}{expectedModCount = modCount=3,} expectedModCount=modCount=3 c u r s o r = 0 , l a s t R e t = − 1 \color{red}{cursor=0,lastRet = -1} cursor=0lastRet=1
③进行hasNext判断,cursor != size;成立,进入循环
④调用next()方法,首先进行checkForComodification()校验, m o d C o u n t = = e x p e c t e d M o d C o u n t \color{red}{modCount == expectedModCount} modCount==expectedModCount,校验通过,返回值,此时 l a s t R e t = 0 ; c u r s o r = 1 \color{red}{lastRet = 0;cursor = 1} lastRet=0;cursor=1

 final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

⑤调用集合remove()方法,modCount++;,此时 m o d C o u n t = 4 ; s i z e = 2 \color{red}{modCount = 4;size = 2} modCount=4;size=2
⑥再次调用hasNext()方法判断,cursor != size;成立,进入循环
⑦调用next()方法进行校验, m o d C o u n t ! = e x p e c t e d M o d C o u n t \color{red}{modCount != expectedModCount} modCount!=expectedModCount,校验未通过,抛出java.util.ConcurrentModificationException异常

总结:

①在使用迭代器remove()操作时,会将更新后的modCountexpectedModCount,两者会得到同步,但是在调用集合的remove()方法后,两个不会进行同步,进而导致在checkForComodification()校验时不通过,抛出java.util.ConcurrentModificationException异常。
②所以,在单线程下使用迭代器是没有问题的,但是在多线程下同时操作集合就不允许了,可以通过fail-fast快速失败机制,快速判断是否存在同时操作问题。因此,集合在多线程下使用是不安全的

📗增强for循环

📫认识增强for循环

增强for循环可以代替Iterator迭代器,可以把它看做简化版的Iterator,和迭代器本质一样,其实它的底层实现就是Iterator迭代器,只能用于遍历集合或数组

📪基本语法

在这里插入图片描述

📬增强for循环的使用

import java.util.ArrayList;
import java.util.List;

public class TestDemo03 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(111);
        list.add(222);
        list.add(333);

        System.out.println("====增强for循环遍历集合====");
        for(Integer i : list) {
            System.out.print(i + " ");
        }
        System.out.println();

        System.out.println("====增强for循环遍历数组====");
        int[] arr = {1,2,3,4,5,6};
        for (int i : arr) {
            System.out.print(i + " ");
        }

    }
}

运行结果:
在这里插入图片描述

📭增强for循环的快捷键

与迭代器一样,增强for循环也有快捷键,输入I回车即可快速生成。
在这里插入图片描述

  • 226
    点赞
  • 758
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
### 回答1: Java中的迭代器(Iterator)是一种对象,它可以遍历一个容器中的元素。迭代器模式是一种设计模式,可以将容器的遍历和实现分离。 Java中的迭代器(Iterator)提供了一种方便的方法来遍历容器中的元素。它提供了三个基本操作: - hasNext(): 返回容器中是否还有下一个元素 - next(): 返回容器中的下一个元素 - remove(): 删除容器中最后一个被next()返回的元素 Java中的迭代器接口是Iterator,其中包含上述三个方法,实现类可以自定义实现这些方法以实现遍历。常见的容器类如List、Set都提供了迭代器的实现。使用迭代器可以更方便地遍历容器中的元素,并且可以在遍历过程中删除元素而不影响其他遍历操作。 ### 回答2: Java迭代器(Iterator)是Java集合框架中一个非常重要的接口,用于遍历并访问集合中的元素。通过使用迭代器,我们可以避免使用传统的for循环方式遍历集合,从而使代码更加简洁、优雅和易于维护。 Java迭代器接口定义了一些常用的方法,使得我们可以在不管具体集合的实现细节的情况下,访问和处理集合中的元素。常用的方法包括: 1. hasNext(): 判断集合是否还有下一个元素。 2. next(): 返回集合中的下一个元素,并将迭代器指针向下一个元素移动。 3. remove(): 移除集合中的当前元素。 下面我们来看一个简单的例子,用来演示如何使用Java迭代器进行遍历: ``` ArrayList<String> list = new ArrayList<String>(); list.add("Java"); list.add("Python"); list.add("Ruby"); Iterator<String> it = list.iterator(); while (it.hasNext()) { String element = it.next(); System.out.println(element); } ``` 在上面的例子中,我们首先定义了一组字符串元素,并将它们添加到了一个ArrayList集合中。然后通过调用iterator()方法,得到了该集合的迭代器。接着,通过使用while循环和next()方法,逐个遍历集合中的元素,并将元素内容输出到控制台上。 需要注意的是,当调用next()方法时,如果集合中已经没有更多的元素可供遍历了,则会抛出NoSuchElementException异常。因此,在使用Java迭代器时,必须首先使用hasNext()方法来检查集合是否还有下一个元素可供遍历。 还需要注意的是,除了一些具体的集合类,如ArrayList,LinkedList, HashSet, TreeMap等,Java迭代器还可以用于自定义集合类。只要实现了Iterator接口,并在实现中定义next()、hasNext()、remove()三个方法即可。 总之,Java迭代器Java集合框架中一项非常重要的功能。通过使用迭代器,我们可以遍历和访问集合中的元素,避免了使用传统的for循环方式,从而使代码更加简洁、优雅和易于维护。 ### 回答3: Java中的迭代器(Iterator)是一种用于遍历集合框架(Collection Framework)中元素的标准方式。Iterator返回的是一个迭代器对象,该对象允许程序员处理集合框架中储存的元素序列。 要使用Iterator遍历一个集合框架中的元素,需要按照以下步骤进行: 1. 调用集合框架中的iterator()方法,返回一个Iterator类型的对象; 2. 使用next()方法取出序列中的每一个元素,next()方法返回序列中的下一个元素,直到序列中的所有元素都被访问完; 3. 使用hasNext()方法判断序列中是否还有下一个元素,如果还有,则返回true,否则返回false。 另外,Iterator类型的对象只能单向遍历,即只能使用next()方法往后遍历,无法往前遍历。 Iterator除了提供基本的遍历操作外,还提供了一些额外的可选操作,例如: 1. remove()方法:从集合中移除迭代器返回的最后一个元素(如果支持的话); 2. forEachRemaining()方法:对集合中的每个元素执行指定的操作,直到所有元素都已被处理完毕或操作引发异常。 在使用Iterator时,需要注意以下几个点: 1. 迭代器只能在对应的集合框架中进行遍历操作,否则会抛出ConcurrentModificationException异常; 2. 迭代器是单向的,一旦遍历到末尾,就无法回到开头; 3. 当集合中的元素被修改、插入或删除时,遍历过程就会中断并抛出异常; 4. 迭代器虽然是fail-fast的,但这并不意味着它一定是线程安全的,如果多个线程同时访问同一个集合,就需要进行加锁、同步等操作,否则可能会出现不可预期的结果。 总的来说,Iterator是一个十分重要的概念,是Java中集合框架遍历元素的标准方式。使用Iterator可以很方便地遍历集合中的元素,并且提供了一些可选操作,但在使用时需要注意迭代器的特殊性质,以免出现异常情况。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WYSCODER

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值