24.集合的遍历(迭代器遍历、增强for、Lambda表达式)

集合的遍历

    • 1. 迭代器遍历
      • 1.1 概述
      • 1.2 方法
      • 1.3 代码示例
      • 1.4 输出结果
      • 1.5 注意事项
    • 2. 增强for遍历
      • 2.1 概述
      • 2.2 方法
      • 2.3 代码示例
      • 2.4 输出结果
      • 2.5 注意事项
    • 3. Lambda表达式遍历
      • 3.1 概述
      • 3.2 方法
      • 3.3 代码示例
      • 3.4 输出结果
      • 3.5 注意事项

常见集合类

Lambda表达式

具体信息请查看 API 帮助文档

1. 迭代器遍历

1.1 概述

迭代器遍历是一种在编程中常用的集合遍历方式。迭代器是一种对象,用于按顺序访问集合中的元素,并且可以进行元素的增删操作。迭代器提供了一种统一的访问集合元素的方式,不依赖于集合的具体实现。

使用迭代器进行集合遍历的基本步骤如下:

  1. 获取迭代器:通过调用集合的 iterator() 方法来获取迭代器对象。不同的集合类具有不同的迭代器实现,因此需要根据具体的集合类型来获取相应的迭代器。

  2. 遍历元素:使用迭代器对象的 hasNext() 方法判断是否还有下一个元素,使用 next() 方法获取当前元素,并将迭代器移动到下一个位置。

  3. 执行操作:对每个元素执行相应的操作,例如读取元素的值、修改元素、删除元素等。

  4. 可选地移除元素:如果需要从集合中移除元素,可以使用迭代器的 remove() 方法。该方法删除的是上一次调用 next() 方法返回的元素。

  5. 循环迭代:重复以上步骤,直到遍历完所有元素,或达到自定义的终止条件。

迭代器遍历的优点是:

  • 可以适用于各种类型的集合,不依赖于集合的具体实现。

  • 在遍历过程中可以进行元素的增删操作,不会引发并发修改异常。

  • 通过迭代器可以实现不同遍历方式,如正向遍历、反向遍历、部分遍历等。

1.2 方法

Iterator中的常用方法 :

方法 描述
Iterator iterator() 获取一个迭代器对象,用于遍历集合中的元素。
boolean hasNext() 判断当前位置是否有元素可以被取出。如果集合还有下一个元素,则返回 true;否则返回 false
E next() 获取当前位置的元素,并将迭代器对象移向下一个位置。
void remove() 删除迭代器对象当前位置的元素。

例如:

       Iterator<String> it = coll.iterator();
       while (it.hasNext()) {
           //next方法的作用:获取元素并移动指针
           String str = it.next();
           System.out.print(str );
       }

细节

  1. 如果迭代器已经指向空元素了,依旧强行调用next方法,则会报错NoSuchElementException;

  2. 迭代器遍历完毕,指针不会复位,依旧指向集合最后,如果想要再次将集合遍历一遍,只能再次创建一个新的迭代器对象,用新的迭代器对象再次遍历;

  3. 循环中只能用一次next方法;

  4. 迭代器遍历时,不能用集合的方法进行增加或者删除(例如:集合提供的remove方法)。
    如果非要删除,可以用迭代器提供的remove方法进行删除。

1.3 代码示例

package text.text02;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
迭代器遍历:
    Iterator iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到

细节:
    1.如果迭代器已经指向空元素了,依旧强行调用next方法,则会报错NoSuchElementException;
    2.迭代器遍历完毕,指针不会复位,依旧指向集合最后,如果想要再次将集合遍历一遍,只能再次创建一个新的迭代器对象,用新的迭代器对象再次遍历;
    3.循环中只能用一次next方法;
    4.迭代器遍历时,不能用集合的方法进行增加或者删除(例如:集合提供的remove方法)。
      如果非要删除,可以用迭代器提供的remove方法进行删除。
 */
public class text24A {
    public static void main(String[] args) {
        //创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        coll.add("eee");

        //调用iterator()方法创建迭代器对象(返回值为迭代器对象)
        Iterator<String> it = coll.iterator();


        //利用循环遍历集合,获取集合中的每一个元素
        while (it.hasNext()) {
            //next方法的作用:获取元素并移动指针
            String str = it.next();
            System.out.print(str + "  ");      //aaa  bbb  ccc  ddd  eee
        }
        System.out.println();


        //1.如果迭代器已经指向空元素了,依旧强行调用next方法,则会报错NoSuchElementException;
        //System.out.println(it.next());       //Exception in thread "main" java.util.NoSuchElementException
        //at java.util.ArrayList$Itr.next(ArrayList.java:864)
        //at text.text02.text24A.main(text24A.java:45)


        //2.迭代器遍历完毕,指针不会复位,依旧指向集合最后
        System.out.println(it.hasNext());      //false,说明该位置没有元素,即指针没有复位
        //如果想要再次将集合遍历一遍,只能再次创建一个新的迭代器对象,用新的迭代器对象再次遍历;
        Iterator<String> iterator = coll.iterator();    //新的迭代器对象
        while (iterator.hasNext()) {
            String str = iterator.next();
            System.out.print(str + "  ");       //aaa  bbb  ccc  ddd  eee
        }
        System.out.println();


        //3.循环中只能用一次next方法;
        /*Iterator iterator1 = coll.iterator();
        while (iterator1.hasNext()) {
            String str1 = iterator1.next();
            String str2 = iterator1.next();
            System.out.println(str1);           //aaa   ccc        Exception in thread "main" java.util.NoSuchElementException at java.util.ArrayList$Itr.next(ArrayList.java:864) at text.text02.text24A.main(text24A.java:65)
            System.out.println(str2);           //bbb   ddd
        }
         */


        //4.迭代器遍历时,不能用集合的方法进行增加或者删除。
        //出现的问题
        /*Iterator iterator2 = coll.iterator();
        while (iterator2.hasNext()) {
            String str = iterator2.next();
            if (str.equals("aaa")) {
                coll.remove(str);
            }
        }
        System.out.println(coll);     //Exception in thread "main" java.util.ConcurrentModificationException(并发修改异常) at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911) at java.util.ArrayList$Itr.next(ArrayList.java:861) at text.text02.text24A.main(text24A.java:75)   */

        //解决方法
        Iterator<String> iterator3 = coll.iterator();
        while (iterator3.hasNext()) {
            String str = iterator3.next();
            if (str.equals("aaa")) {
                iterator3.remove();
            }
        }
        System.out.println(coll);        //[bbb, ccc, ddd, eee]
    }
}

1.4 输出结果

  • 利用循环遍历集合,获取集合中的每一个元素

    在这里插入图片描述

  • 如果迭代器已经指向空元素了,依旧强行调用next方法,则会报错NoSuchElementException;
    在这里插入图片描述

  • 迭代器遍历完毕,指针不会复位,依旧指向集合最后
    在这里插入图片描述

  • 如果想要再次将集合遍历一遍,只能再次创建一个新的迭代器对象,用新的迭代器对象再次遍历;
    在这里插入图片描述

  • 循环中只能用一次next方法;
    在这里插入图片描述

  • 迭代器遍历时,不能用集合的方法进行增加或者删除

    • 出现的问题
      24.集合的遍历(迭代器遍历、增强for、Lambda表达式)_第1张图片

    • 解决方法
      在这里插入图片描述

1.5 注意事项

  1. 并发修改异常:在迭代器遍历过程中,如果直接使用集合的方法(如 add()remove())修改集合的结构,可能会引发并发修改异常 ConcurrentModificationException。为避免此类异常,应该使用迭代器自身的 remove() 方法来删除元素。

  2. 一次性遍历:迭代器通常是单向的,即不支持回溯或跳跃遍历集合。所以,在开始遍历之前,应确认不会在遍历过程中修改集合的结构,以防止出现元素丢失、重复遍历等问题。

  3. 删除元素时机:当需要在迭代器遍历过程中删除元素时,应先调用 next() 方法获取当前元素,然后再调用迭代器的 remove() 方法删除元素。否则,会导致删除错误或引发异常。

  4. 遍历性能:迭代器遍历是一种逐个访问集合元素的方式,对于大型集合或需要频繁遍历的场景,可能会对性能有一定影响。如果对性能有更高要求,可以考虑其他遍历方式,如增强型 for 循环、Stream API 等。

  5. 不同类型的集合可能具有不同的迭代器实现方式,因此在使用迭代器进行遍历时,需要根据具体集合类型来获取相应的迭代器。

2. 增强for遍历

2.1 概述

增强for循环(Enhanced for Loop),也被称为for-each循环,是Java中一种用于遍历集合或数组元素的简化循环结构。它提供了一种更简洁、易读的方式来遍历集合中的元素,无需手动使用索引或迭代器。

增强for循环的主要优点是简化了遍历集合或数组的代码,使代码更加简洁易读。

此外,增强for循环具有以下特点:

  • 不需要手动控制索引或迭代器,遍历过程更加简便。

  • 仅适用于遍历访问集合中的元素,无法获取当前元素的索引或修改集合结构。

  • 不需要额外考虑越界或空元素的问题,减少了容易出错的可能性。

需要注意的是,增强for循环在遍历过程中是只读的,无法修改集合中的元素。如果需要对元素进行修改,可以使用普通for循环或迭代器进行遍历。

增强for循环:

  • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

  • 实现Iterable接口的类才可以使用迭代器和增强for

  • 简化数组和Collection集合的遍历

2.2 方法

格式:

for(数据类类型 变量名 : 集合/数组){

    }

细节:

  1. 变量名其实是一个第三方变量,在循环的过程中一次表示集合中的每一个数据

  2. 修改增强for中的变量值,不会改变集合中的原有数据

2.3 代码示例

package text.text02;

import java.util.ArrayList;
import java.util.Collection;

/*
增强for循环:
- 它是JDK5之后出现的,其内部原理是一个Iterator迭代器
- 实现Iterable接口的类才可以使用迭代器和增强for
- 简化数组和Collection集合的遍历

格式:for(数据类类型 变量名 : 集合/数组){

    }

细节:
    1,变量名其实是一个第三方变量,在循环的过程中一次表示集合中的每一个数据
    2. 修改增强for中的变量值,不会改变集合中的原有数据
 */
public class text25A {
    public static void main(String[] args) {
        //创建集合并添加数据
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");

        //利用增强for循环遍历集合
        //String为数据类型
        //s:为变量名
        //coll:为集合的名字
        for (String s : coll) {
            System.out.print(s + "\t");   //aaa	bbb	ccc	ddd
        }
        System.out.println();
        System.out.println(coll);       //[aaa, bbb, ccc, ddd]
    }
}

2.4 输出结果

  • 利用增强for循环遍历集合

24.集合的遍历(迭代器遍历、增强for、Lambda表达式)_第2张图片

2.5 注意事项

  1. 只读访问:增强for循环是只读访问集合或数组元素的,无法在循环体中修改集合或数组的结构。如果尝试在循环体中修改集合或数组,比如使用 collection.remove(element),将会引发 ConcurrentModificationException 异常。

  2. 局部变量:增强for循环中声明的元素变量是局部变量,其作用域只在当前循环中有效。在循环外部无法访问到该变量。

  3. 不支持索引操作:增强for循环无法获取当前元素的索引值。如果需要索引值进行操作,需要使用传统的for循环或者配合其他变量来实现。

  4. 遍历顺序:增强for循环按照集合或数组中元素的顺序进行遍历,无法保证按照特定的顺序(比如插入顺序或排序顺序)进行遍历。

  5. 判空处理:在使用增强for循环遍历集合或数组之前,需要确保集合或数组不为null且不为空。否则,如果对一个空集合或数组进行遍历,将会导致 NullPointerException 异常。

  6. 增强for循环适用性:增强for循环适用于遍历实现了 Iterable 接口的集合类(如List、Set等)或数组。对于其他类型的集合或自定义类,可能无法使用增强for循环,需要使用传统的for循环或迭代器来进行遍历。

3. Lambda表达式遍历

3.1 概述

Lambda表达式是Java 8引入的一种函数式编程的特性,它提供了一种更简洁、灵活的方式来表示匿名函数。在遍历集合或数组时,Lambda表达式可以与函数式接口结合使用,实现更简洁的遍历代码。

Lambda表达式在遍历集合或数组中的元素时,通常结合Stream API来使用。Stream API提供了一种函数式的流式操作方式,可以通过链式调用一系列方法来处理集合或数组中的元素。

在Lambda表达式中,箭头符号->将参数列表与函数体分隔开来。参数列表可以省略参数类型,如果只有一个参数,还可以省略小括号。函数体可以是单个表达式或代码块。

3.2 方法

Lambda表达式遍历:

     default void forEach(Consumer<? super T> action)

3.3 代码示例

package text.text02;

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;

/*
Lambda表达式遍历:
     default void forEach(Consumer action):
 */
public class text26A {
    public static void main(String[] args) {
        //创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");

        //先利用匿名内部类遍历
        coll.forEach(new Consumer<String>() {
            //底层原理:其实也会自己遍历集合,一次得到每一个元素,把得到的每一个元素,传递给下面的accep方法
            //s依次表示集合中的每一个元素
            @Override
            public void accept(String s) {
                System.out.print(s + "\t");       //aaa	bbb	ccc	ddd
            }
        });

        System.out.println();

        //利用Lambda表达式遍历
        coll.forEach(s -> System.out.print(s + "\t"));      //aaa	bbb	ccc	ddd
    }
}

3.4 输出结果

  • 先利用匿名内部类遍历
    在这里插入图片描述

  • 利用Lambda表达式遍历
    在这里插入图片描述

3.5 注意事项

  1. 函数式接口:Lambda表达式需要与函数式接口(Functional Interface)结合使用。函数式接口是只有一个抽象方法的接口,可以使用Lambda表达式作为该接口的实现。确保目标上下文期望的是函数式接口,否则无法使用Lambda表达式。

  2. Lambda表达式语法:Lambda表达式由->箭头符号分成两个部分:左侧是参数列表,右侧是函数体。参数列表可以省略参数类型,如果只有一个参数,还可以省略小括号。函数体可以是单个表达式或代码块。

  3. 变量捕获:Lambda表达式可以访问外部的局部变量或成员变量,但是这些变量必须是隐式具有finaleffectively final特性的(即只能赋值一次,不可再修改)。这是因为Lambda表达式内部会创建一个对变量的拷贝。

  4. 异常处理:Lambda表达式中的异常必须显式处理或向上抛出,不能直接在函数体中捕获或抛出异常。如果Lambda表达式中抛出了异常,并且函数式接口的抽象方法没有声明抛出该异常,将会导致编译错误。

  5. 对象方法引用:如果Lambda表达式的函数体只是调用一个已存在的方法,可以使用对象方法引用(Object Method Reference)来代替Lambda表达式,提高代码的可读性。

  6. 基本类型:Lambda表达式的参数和返回值可以是任意类型,包括基本类型和引用类型。但是在某些情况下,由于自动装箱和拆箱的性能开销,使用基本类型可能更高效。

  7. 嵌套Lambda表达式:Lambda表达式可以嵌套使用,即在Lambda表达式中再使用Lambda表达式。但是要注意避免过度嵌套,以保持代码的可读性和维护性。

你可能感兴趣的:(#,Java基础语法,java,javascript,算法)