24.集合的遍历(单列集合、双列集合)

常见集合类

Lambda表达式

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

1. Collection 单列集合

单列集合(Collection)的特点:

  1. 无序性:一般情况下,单列集合不保证元素的顺序,每次遍历的顺序可能不同。

  2. 可重复性:单列集合中可以包含重复的元素,允许存储多个相同的对象。

  3. 动态大小:单列集合的大小是动态可变的,可以根据需要增加或减少元素的个数。

  4. 提供统一的访问方式:可以使用迭代器(Iterator)遍历元素,或者通过索引访问元素。

1.1 迭代器遍历

1.1.1 概述

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

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

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

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

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

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

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

迭代器遍历的优点是:

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

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

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

1.1.2 方法

Iterator中的常用方法 :

方法描述
Iterator<E> 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.1.3 代码示例

package text.text02;

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

/*
迭代器遍历:
    Iterator<E> 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<String> 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<String> 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.1.4 输出结果

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

    在这里插入图片描述

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

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

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

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

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

    • 出现的问题
      在这里插入图片描述

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

1.1.5 注意事项

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

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

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

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

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

1.1.6 源码分析

迭代器遍历相关的三个方法:

  • Iterator iterator() :获取一个迭代器对象

  • boolean hasNext() :判断当前指向的位置是否有元素

  • E next() :获取当前指向的元素并移动指针

在这里插入图片描述

1.2 增强for遍历

1.2.1 概述

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

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

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

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

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

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

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

增强for循环:

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

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

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

1.2.2 方法

格式:

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

    }

细节:

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

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

1.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]
    }
}

1.2.4 输出结果

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

在这里插入图片描述

1.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循环或迭代器来进行遍历。

1.3 Lambda表达式遍历

1.3.1 概述

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

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

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

1.3.2 方法

Lambda表达式遍历:

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

1.3.3 代码示例

package text.text02;

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

/*
Lambda表达式遍历:
     default void forEach(Consumer<? super T> 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
    }
}

1.3.4 输出结果

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

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

1.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表达式。但是要注意避免过度嵌套,以保持代码的可读性和维护性。

2. Map双列集合

双列集合(Map)的特点:

  1. 键值对:双列集合以键(key)和值(value)的方式存储数据,每个元素是一个键值对对象。

  2. 键的唯一性:每个键是唯一的,不允许重复的键。但值可以重复。

  3. 无序性:Map的实现类(如HashMap)通常不保证元素的顺序,每次遍历的顺序可能不同。

  4. 可通过键快速访问值:通过给定一个键的值,可以快速找到对应的值。

  5. 动态大小:Map的大小是动态可变的,可以根据需要增加或减少键值对的个数。

方法介绍:

方法名说明
V get(Object key)根据键获取值
Set keySet()获取所有键的集合
Collection values()获取所有值的集合
Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合

2.1 键找值遍历

2.1.1 概述

键找值的遍历是指在双列集合(如Map)中,通过遍历键来获取对应的值的过程。

  1. 获取键集合:首先,通过调用Map的keySet()方法获取所有的键集合。这个方法将返回一个Set集合,其中包含了Map中所有的键。

  2. 遍历键集合:使用迭代器(Iterator)或增强型for循环,依次遍历键集合中的每个键。

  3. 通过键获取值:在遍历过程中,通过调用Map的get(key)方法,传入当前遍历到的键,来获取对应的值。

  4. 处理获取到的值:根据具体的需求,对获取到的值进行相应的处理操作。

需要注意的是,遍历过程中的键的顺序通常是不确定的,特别是在使用的是HashMap这样的实现类时。如果需要按特定的顺序遍历键集合,可以考虑使用TreeMap这样有序的Map实现类。

2.1.2 代码示例

package text.text02;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

/*
Map集合的第一种遍历方式:键找值
1.获取所有的键,把这些键放到一个单列集合中      keySet()方法
2.遍历单列集合,获取每一个键
3.利用Map集合里面的get方法获取对应的值
 */
public class text46 {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<>();

        //添加元素
        map.put("刘备", "孙尚香");
        map.put("李白", "王昭君");
        map.put("孙策", "小乔");
        map.put("周瑜", "小乔");
        map.put("孙悟空", "露娜");
        map.put("亚瑟", "安琪拉");

        //遍历集合
        //调用KeySet方法,将map集合中的所有的键放到单列集合中
        Set<String> ks = map.keySet();

        System.out.println("===========利用单列集合中的增强for的方式遍历===========");
        //1.利用单列集合中的增强for的方式遍历
        for (String key : ks) {
            //调用Map集合里面的get方法获取对应的值
            String value = map.get(key);
            System.out.println(key + " = " + value);
        }

        System.out.println("===========利用单列集合中的迭代器的方式遍历===========");
        //2.利用单列集合中的迭代器的方式遍历
        //调用单列集合的遍历方式遍历单列集合,获取单列集合里面的每一个数据(键)
        Iterator<String> it = ks.iterator();
        while (it.hasNext()) {
            String key = it.next();
            //调用Map集合里面的get方法,获取到对应的值
            String value = map.get(key);
            System.out.println(key + " = " + value);
        }

        System.out.println("===========利用单列集合中的Lambda表达式的方式遍历===========");
        //3.利用单列集合中的Lambda表达式的方式遍历
        ks.forEach(new Consumer<String>() {
            @Override
            public void accept(String key) {
                //调用Map集合里面的get方法,获取到对应的值
                String value = map.get(key);
                System.out.println(key + " = " + value);
            }
        });
    }
}

2.1.3 输出结果

  1. 利用单列集合中的增强for的方式遍历
    在这里插入图片描述
  2. 利用单列集合中的迭代器的方式遍历
    在这里插入图片描述
  3. 利用单列集合中的Lambda表达式的方式遍历
    在这里插入图片描述

2.1.4 注意事项

  1. 空指针判断:在获取键对应的值之前,最好先判断键是否存在。可以使用containsKey()方法来判断指定键是否存在于Map中。

  2. 并发修改:在进行键找值的遍历时,如果在遍历过程中对Map进行了修改(如增加、删除键值对),可能会导致ConcurrentModificationException异常。为了避免这种情况,可以通过使用迭代器的remove()方法进行删除操作,或者使用并发安全的Map实现类(如ConcurrentHashMap)来避免此问题。

  3. 顺序性:一般情况下,HashMap等实现类的遍历是无序的,即遍历键集合得到的键的顺序可能是不确定的。如果需要按特定的顺序遍历键集合,可以选择使用TreeMap等有序的Map实现类。

  4. 性能考虑:当需要频繁进行键找值的操作时,可以考虑使用HashMap这样的哈希表实现类,因为哈希表的查找时间复杂度为O(1)。而TreeMap等有序实现类的查找时间复杂度为O(logN),可能在大规模数据操作时性能较低。

  5. 存储的键对象要正确实现equals()和hashCode()方法:在进行键找值的遍历和查找操作时,Map会依赖键对象的equals()和hashCode()方法来判断键是否相等和生成哈希码。所以要确保存储的键对象正确实现了这两个方法,以保证键的唯一性和查找的准确性。

2.2 键值对遍历

2.2.1 概述

键值对遍历是指在双列集合(如Map)中,同时遍历键和对应的值的过程。

  1. 获取键值对集合:首先,通过调用Map的entrySet()方法获取所有的键值对集合。这个方法将返回一个Set集合,其中包含了Map中所有的键值对。

  2. 遍历键值对集合:使用迭代器(Iterator)或增强型for循环,依次遍历键值对集合中的每个键值对。

  3. 获取键和值:在遍历过程中,每次迭代返回一个键值对对象。通过调用键值对对象的getKey()方法可以获取当前迭代的键,通过调用getValue()方法可以获取对应的值。

  4. 处理获取到的键和值:根据具体的需求,对获取到的键和值进行相应的处理操作。例如,输出键和值、进行计算、修改等。

需要注意的是,遍历过程中的键值对的顺序通常是不确定的,特别是在使用的是HashMap这样的实现类时。如果需要按特定的顺序遍历键值对集合,可以考虑使用TreeMap这样有序的Map实现类。

2.2.2 代码示例

package text.text02;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

/*
Map集合的第二种遍历方式:键值对
1.通过Map集合里面的entrySet方法,获取所有的键值对对象并放入一个Set集合中
    Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合   Map是外接接口,Entry是内接接口,Map.Entry<K,V>是Set集合的泛型,<K,V>是Map集合的泛型。
2.遍历Set集合,得到里面的每一个键值对对象
3.通过Map集合里的getKey方法获取键;通过Map集合里的getValue方法获取值
 */
public class text47 {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<>();

        //添加元素
        map.put("刘备", "孙尚香");
        map.put("李白", "王昭君");
        map.put("孙策", "小乔");
        map.put("周瑜", "小乔");
        map.put("孙悟空", "露娜");
        map.put("亚瑟", "安琪拉");

        //遍历集合
        //通过调用Map集合中的entrySet方法获取所有的键值对对象
        Set<Map.Entry<String, String>> entries = map.entrySet();
        //遍历Set集合获取每一个对应的键和值

        System.out.println("================利用迭代器遍历================");
        //1.利用迭代器遍历
        Iterator<Map.Entry<String, String>> it = entries.iterator();
        while (it.hasNext()) {
            //获取单列集合里的键值对对象
            Map.Entry<String, String> set = it.next();
            String key = set.getKey();//获取键
            String value = set.getValue();//获取值
            System.out.println(key + " = " + value);
        }

        System.out.println("================利用增强for遍历================");
        //2.利用增强for遍历
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();//获取键
            String value = entry.getValue();//获取值
            System.out.println(key + " = " + value);
        }

        System.out.println("================利用lambda表达式================");
        //3.利用lambda表达式
        entries.forEach(new Consumer<Map.Entry<String, String>>() {
            @Override
            public void accept(Map.Entry<String, String> entry) {
                String key = entry.getKey();//获取键
                String value = entry.getValue();//获取值
                System.out.println(key + " = " + value);
            }
        });
    }
}

2.2.3 输出结果

  1. 利用迭代器遍历
    在这里插入图片描述
  2. 利用增强for遍历
    在这里插入图片描述
  3. 利用lambda表达式
    在这里插入图片描述

2.2.4 注意事项

  1. 空指针判断:在遍历过程中,最好先判断键值对对象是否为空,以避免空指针异常。可以使用entrySet()方法获取的键值对集合进行判断。

  2. 并发修改:在进行键值对遍历时,如果在遍历过程中对Map进行了修改(如增加、删除键值对),可能会导致ConcurrentModificationException异常。为了避免这种情况,可以通过使用迭代器的remove()方法进行删除操作,或者使用并发安全的Map实现类(如ConcurrentHashMap)来避免此问题。

  3. 顺序性:一般情况下,HashMap等实现类的遍历是无序的,即遍历键值对集合得到的键值对的顺序可能是不确定的。如果需要按特定的顺序遍历键值对集合,可以选择使用TreeMap等有序的Map实现类。

  4. 存储的键对象要正确实现equals()和hashCode()方法:在进行键值对遍历和查找操作时,Map会依赖键对象的equals()和hashCode()方法来判断键是否相等和生成哈希码。所以要确保存储的键对象正确实现了这两个方法,以保证键的唯一性和查找的准确性。

  5. 性能考虑:当需要频繁进行键值对的遍历和操作时,可以考虑使用HashMap这样的哈希表实现类,因为哈希表的查找时间复杂度为O(1)。而TreeMap等有序实现类的查找时间复杂度为O(logN),可能在大规模数据操作时性能较低。

2.3 结合lambda表达式遍历

2.3.1 概述

结合lambda遍历Map集合:

default void forEach(BiConsumer< ? super k , ? super v > action)    

BiConsumer是一个函数式接口

  1. 获取键值对集合:首先,通过调用Map的entrySet()方法获取所有的键值对集合。这个方法将返回一个Set集合,其中包含了Map中所有的键值对。

  2. 使用Lambda表达式遍历键值对集合:可以使用forEach()方法结合Lambda表达式对键值对集合进行遍历。这样可以直接在Lambda表达式中定义遍历过程的具体操作。

  3. 处理键和值:在Lambda表达式中可以对键和值进行相应的处理操作。通过参数列表中的两个参数可以分别获取键和值。可以根据具体的需求对键和值进行输出、计算、修改等操作。

  4. lambda表达式的语法:Lambda表达式的一般语法为(参数列表) -> { 方法体 }。在遍历键值对时,可以将遍历的逻辑放在方法体内。例如,(key, value) -> System.out.println(key + ": " + value)表示遍历过程中将键和值打印输出。

使用Lambda表达式可以简化键值对的遍历代码,使得代码更加简洁和可读。此外,由于Lambda表达式可以通过并行流和串行流进行并行化处理,还可以提高遍历和处理的效率。

需要注意的是,Lambda表达式在Java 8及之后的版本中引入,所以需要确保项目的Java版本支持Lambda表达式的使用。

2.3.2 代码示例

package text.text02;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

/*
Map集合的第三种遍历方式:结合lambda表达式遍历Map集合
default void forEach(BiConsumer< ? super k , ? super v > action)    结合lambda遍历Map集合       BiConsumer是一个函数式接口
方法底层:
forEach其实就是利用第二种方式进行遍历,依次得到每一个键和值,再调用accept方法
entrySet()等同于Set<Map.Entry<String, String>> entries = map.entrySet()中的entries,只是省略了返回值

 default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }
 */
public class text48 {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<>();

        //添加元素
        map.put("刘备", "孙尚香");
        map.put("李白", "王昭君");
        map.put("孙策", "小乔");
        map.put("周瑜", "小乔");
        map.put("孙悟空", "露娜");
        map.put("亚瑟", "安琪拉");

        //结合lambda表达式遍历Map集合
        map.forEach(new BiConsumer<String, String>() {
            @Override
            public void accept(String key, String value) {
                System.out.println(key + " = " + value);
            }
        });
    }
}

2.3.3 输出结果

  • 结合lambda表达式遍历Map集合
    在这里插入图片描述

2.3.4 注意事项

  1. Lambda表达式的参数类型:在Lambda表达式中,可以使用自动类型推断省略参数的类型声明。但是,在遍历键值对时,建议明确指定键值对的参数类型,以提高代码的可读性和可维护性。

  2. Lambda表达式的参数变量可能为null:在遍历中,Map的键或值可能为null。在使用Lambda表达式处理键或值时,需要注意空指针异常。建议在Lambda表达式中对参数进行null判断,或使用Optional类来确保安全访问。

  3. 并发修改:在使用Lambda表达式进行键值对遍历时,如果在遍历过程中对Map进行了修改(如增加、删除键值对),可能会导致ConcurrentModificationException异常。为了避免这种情况,可以使用并发安全的Map实现类,例如ConcurrentHashMap。

  4. Lambda表达式的参数命名:为了代码的可读性,建议给Lambda表达式的参数起有意义的名称,以便在Lambda表达式中使用参数时有清晰的语义。例如,(key, value) -> {...},其中keyvalue是有意义的参数名。

  5. 性能考虑:尽管使用Lambda表达式可以简化代码,但在处理大规模数据时,可能需要考虑性能问题。Lambda表达式的执行效率与具体的操作有关,对于复杂的操作,可能需要权衡代码简洁性和性能效率。

  • 45
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是Java单列集合双列集合遍历方法: 1. 单列集合遍历: - 使用迭代器(Iterator)进行遍历: ```java List<String> list = new ArrayList<>(); list.add("小鲁班"); list.add("貂蝉"); list.add("后羿"); list.add("白起"); list.add("亚瑟"); list.add("百里守约"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String name = iterator.next(); System.out.print(name + " "); } // 输出结果:小鲁班 貂蝉 后羿 白起 亚瑟 百里守约 ``` - 使用增强for循环进行遍历: ```java List<String> list = new ArrayList<>(); list.add("小鲁班"); list.add("貂蝉"); list.add("后羿"); list.add("白起"); list.add("亚瑟"); list.add("百里守约"); for (String name : list) { System.out.print(name + " "); } // 输出结果:小鲁班 貂蝉 后羿 白起 亚瑟 百里守约 ``` 2. 双列集合遍历: - 使用迭代器(Iterator)进行遍历: ```java Map<String, Integer> map = new HashMap<>(); map.put("小鲁班", 1); map.put("貂蝉", 2); map.put("后羿", 3); map.put("白起", 4); map.put("亚瑟", 5); map.put("百里守约", 6); Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); String name = entry.getKey(); int value = entry.getValue(); System.out.println(name + ": " + value); } // 输出结果: // 小鲁班: 1 // 貂蝉: 2 // 后羿: 3 // 白起: 4 // 亚瑟: 5 // 百里守约: 6 ``` - 使用增强for循环进行遍历: ```java Map<String, Integer> map = new HashMap<>(); map.put("小鲁班", 1); map.put("貂蝉", 2); map.put("后羿", 3); map.put("白起", 4); map.put("亚瑟", 5); map.put("百里守约", 6); for (Map.Entry<String, Integer> entry : map.entrySet()) { String name = entry.getKey(); int value = entry.getValue(); System.out.println(name + ": " + value); } // 输出结果: // 小鲁班: 1 // 貂蝉: 2 // 后羿: 3 // 白起: 4 // 亚瑟: 5 // 百里守约: 6 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

酷小洋

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

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

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

打赏作者

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

抵扣说明:

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

余额充值