Java集合面试题&知识点总结(中篇)

2023-10-31 14:13:56 浏览数 (1)

1、Java基础面试题问题
  • 问题 21. 介绍一下 Set 集合,以及它有怎样的特性?
  • 问题 22. 介绍一下 Set 集合,有哪些常见的方法?
  • 问题 23. 介绍一下 HashSet 的底层结构和相关原理
  • 问题 24. 介绍一下 LinkedHashSet 的底层结构和相关原理
  • 问题 25. 介绍一下 TreeSet 的底层结构和相关原理
  • 问题 26. 请解释一下 Java 中的 EnumSet?
  • 问题 27. 请解释一下 Java 中的 SortedSet?
  • 问题 28. 请解释一下 Java 中的 NavigableSet
  • 问题 29. 请解释一下 Java 中的 Comparable 接口?
  • 问题 30. 请解释一下 Java 中的 Comparator 接口?
  • 问题 31. 请解释一下 Java 中的 CopyOnWrite
  • 问题 32. 请解释一下 Java 中的 CopyOnWriteArrayList
  • 问题 33. 简述什么是 Fail Fast?
  • 问题 34. 简述什么是 Fail Safe?
  • 问题 35. 请解释一下 Java 中的 ConcurrentModificationException?
  • 问题 36. Java 中迭代器 Iterator 是什么?
  • 问题 37. Java 中 Iterator 和 ListIterator 有什么区别?
  • 问题 38. 为什么使用 Iterator 删除元素更加安全?
  • 问题 39. 如何在 Java 中使用 Java 8 的 Stream API 处理集合?
  • 问题 40. 如何在 Java 中使用 Java 8 的 forEach 方法遍历集合?

2、Java基础面试题解答
2.1、JavaSet集合相关-特性&方法
  • 问题 21. 介绍一下 Set 集合,以及它有怎样的特性?

解答:Set 是 Java 集合框架中的一个接口,它继承自 Collection 接口。Set 集合中的元素是无序的,并且不包含重复的元素。

Set 集合的主要特性包括:

  1. 无序:Set 集合中的元素没有特定的顺序。也就是说,我们不能通过索引来访问 Set 集合中的元素。
  2. 不可重复:Set 集合不允许插入重复的元素。如果试图插入已经存在的元素,Set 集合不会报错,但是插入操作不会有任何效果。
  3. 元素可为 null:Set 集合中可以添加 null 元素。

Java 中的 HashSetLinkedHashSetTreeSet 都是 Set 接口的实现类,它们具有上述的 Set 特性,但是在内部实现和性能上有所不同。例如,HashSet 是基于哈希表实现的,插入和查询的性能较高;LinkedHashSet 是在 HashSet 的基础上,增加了链表来保证元素的插入顺序;TreeSet 是基于红黑树实现的,元素会按照自然顺序或者自定义的顺序进行排序。

  • 问题 22. 介绍一下 Set 集合,有哪些常见的方法?

解答:Set 接口在 Collection 接口的基础上,没有新增任何方法,主要的方法都继承自 Collection 接口。以下是 Set 接口中一些常见的方法:

  1. boolean add(E e):向集合中添加元素,如果集合已经包含该元素,则返回 false
  2. void clear():清空集合,移除所有元素。
  3. boolean contains(Object o):判断集合是否包含指定的元素。
  4. boolean isEmpty():判断集合是否为空。
  5. Iterator<E> iterator():返回一个用于遍历集合的迭代器。
  6. boolean remove(Object o):从集合中移除指定的元素。
  7. int size():返回集合中元素的数量。
  8. Object[] toArray():将集合转换为数组。

以上就是 Set 接口中一些常见的方法,它们提供了丰富的功能,使得我们可以方便地对集合进行操作。

2.2、JavaSet集合相关-具体实现
  • 问题 23. 介绍一下 HashSet 的底层结构和相关原理

解答:HashSet 是基于 HashMap 实现的,底层采用 HashMap 来保存所有元素。因此,HashSet 的数据结构就是 HashMap 的数据结构。

HashMap 是一个散列表,它存储的内容是键值对 (key-value)。HashMap 通过键的哈希值进行快速查找,具有较高的查找和插入速度。

HashSet 中的元素实际上作为 HashMap 的键存在,而 HashMap 的值则存储了一个固定的对象 PRESENT。因此,HashSet 中的元素不能重复,这是因为 HashMap 的键不能重复。

HashSet 的操作都是基于 HashMap 的操作来实现的,例如添加元素、删除元素、查找元素等。

  • 问题 24. 介绍一下 LinkedHashSet 的底层结构和相关原理

解答:LinkedHashSetHashSet 的一个子类,它的底层是基于 LinkedHashMap 来实现的。

LinkedHashMapHashMap 的一个子类,它在 HashMap 的基础上,增加了一个双向链表。这个双向链表连接了所有的键值对,定义了键值对的迭代顺序。迭代的顺序可以是插入顺序,也可以是访问顺序。

LinkedHashSet 中的元素实际上作为 LinkedHashMap 的键存在,而 LinkedHashMap 的值则存储了一个固定的对象 PRESENT。因此,LinkedHashSet 中的元素不能重复,这是因为 LinkedHashMap 的键不能重复。

LinkedHashSet 的操作都是基于 LinkedHashMap 的操作来实现的,例如添加元素、删除元素、查找元素等。由于 LinkedHashSet 维护了一个运行于所有条目的双向链表,因此,可以在用迭代器遍历 LinkedHashSet 时,得到一个确定的顺序(插入的顺序)。

  • 问题 25. 介绍一下 TreeSet 的底层结构和相关原理

解答:TreeSet 是基于 TreeMap 实现的,底层采用 TreeMap 来保存所有元素。因此,TreeSet 的数据结构就是 TreeMap 的数据结构。

TreeMap 是一个红黑树(自平衡的排序二叉树)。它存储的内容是键值对 (key-value)。TreeMap 通过键的自然顺序或者自定义的比较器进行排序,具有较高的查找和插入速度。

TreeSet 中的元素实际上作为 TreeMap 的键存在,而 TreeMap 的值则存储了一个固定的对象 PRESENT。因此,TreeSet 中的元素不能重复,这是因为 TreeMap 的键不能重复。

TreeSet 的操作都是基于 TreeMap 的操作来实现的,例如添加元素、删除元素、查找元素等。由于 TreeSet 是基于 TreeMap 实现的,所以 TreeSet 的元素是有序的,元素的排序方式取决于构造 TreeSet 时提供的 Comparator,或者依赖元素的自然顺序(Comparable)。

TreeSetSortedSet 接口的一个实现类,它提供了一个基于树结构的 Set,元素可以按照自然顺序或者自定义的比较器进行排序。

  • 问题 26. 请解释一下 Java 中的 EnumSet?

解答:EnumSet 是 Java 中的一个专门为枚举类型设计的集合类。它继承自 AbstractSet,并实现了 Set 接口。

以下是 EnumSet 的一些特性:

  1. EnumSet 中的所有元素都必须来自同一个枚举类型,它在创建时显式或隐式地指定。
  2. EnumSet 是有序的,其元素的顺序就是它们在源代码中的顺序。
  3. EnumSet 集合类的实现是非常高效和快速的,其大部分操作都是通过位运算实现的。
  4. EnumSet 不允许使用 null 元素,如果尝试添加 null 元素,它会抛出 NullPointerException
  5. EnumSet 是线程不安全的,如果多个线程同时修改 EnumSet,需要进行同步处理。

以下是创建 EnumSet 的一些方法:

  1. EnumSet.allOf(Class<E> elementType):创建一个包含指定枚举类型的所有元素的 EnumSet
  2. EnumSet.noneOf(Class<E> elementType):创建一个指定枚举类型的空 EnumSet
  3. EnumSet.of(E first, E... rest):创建一个最初包含指定元素的 EnumSet
  4. EnumSet.range(E from, E to):创建一个包含从 from 元素到 to 元素范围内的所有元素的 EnumSet
  5. EnumSet.copyOf(Collection<E> c)EnumSet.copyOf(EnumSet<E> s):创建一个与指定 EnumSet 具有相同元素类型的 EnumSet,最初包含相同的元素(如果有的话)。
  • 问题 27. 请解释一下 Java 中的 SortedSet?

解答:SortedSet 是 Java 集合框架中的一个接口,它继承自 Set 接口。SortedSet 接口为集合中的元素提供了一个总的排序。

以下是 SortedSet 的一些特性:

  1. SortedSet 中的元素按照自然顺序或者自定义的比较器(Comparator)进行排序。
  2. SortedSet 不允许插入 null 元素。如果尝试插入 null 元素,它会抛出 NullPointerException
  3. SortedSet 是线程不安全的,如果多个线程同时修改 SortedSet,需要进行同步处理。

以下是 SortedSet 的一些主要方法:

  1. Comparator<? super E> comparator():返回用于对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回 null
  2. E first():返回此 set 中当前第一个(最低)元素。
  3. SortedSet<E> headSet(E toElement):返回此 set 的部分视图,其元素严格小于 toElement
  4. E last():返回此 set 中当前最后一个(最高)元素。
  5. SortedSet<E> subSet(E fromElement, E toElement):返回此 set 的部分视图,其元素的范围从 fromElement(包括)到 toElement(不包括)。
  6. SortedSet<E> tailSet(E fromElement):返回此 set 的部分视图,其元素大于等于 fromElement
  • 问题 28. 请解释一下 Java 中的 NavigableSet

解答:NavigableSet 是 Java 集合框架中的一个接口,它继承自 SortedSet 接口。NavigableSet 描述了一种可以通过搜索方法导航的数据结构。

以下是 NavigableSet 的一些特性:

  1. NavigableSet 中的元素按照自然顺序或者自定义的比较器(Comparator)进行排序。
  2. NavigableSet 提供了多种导航方法,例如获取小于/大于某个元素的最大/最小元素等。
  3. NavigableSet 不允许插入 null 元素。如果尝试插入 null 元素,它会抛出 NullPointerException
  4. NavigableSet 是线程不安全的,如果多个线程同时修改 NavigableSet,需要进行同步处理。

以下是 NavigableSet 的一些主要方法:

  1. E lower(E e):返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null
  2. E floor(E e):返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null
  3. E ceiling(E e):返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null
  4. E higher(E e):返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null
  5. E pollFirst():获取并移除此 set 中的第一个(最低)元素;如果此 set 为空,则返回 null
  6. E pollLast():获取并移除此 set 中的最后一个(最高)元素;如果此 set 为空,则返回 null

TreeSetNavigableSet 接口的一个实现类,它提供了一个基于树结构的 Set,元素可以按照自然顺序或者自定义的比较器进行排序。

2.3、Java排序接口相关
  • 问题 29. 请解释一下 Java 中的 Comparable 接口?

解答:Comparable 是 Java 中的一个接口,用于定义对象之间的自然排序规则。如果一个类实现了 Comparable 接口,那么它的对象就可以进行比较和排序。

Comparable 接口定义了一个 compareTo 方法,需要实现类进行重写。compareTo 方法接收一个同类型的对象作为参数,返回一个整数,有三种可能:

  1. 返回 0,表示 this 等于参数对象;
  2. 返回正数,表示 this 大于参数对象;
  3. 返回负数,表示 this 小于参数对象。

例如,下面的代码定义了一个 Person 类,实现了 Comparable 接口,按照年龄进行排序:

代码语言:javascript复制
public class Person implements Comparable<Person> {
    private String name;
    private int age;

    // ... 省略构造方法和 getter、setter 方法 ...

    @Override
    public int compareTo(Person other) {
        return this.age - other.age;
    }
}

这样,我们就可以对 Person 对象进行排序:

代码语言:javascript复制
List<Person> people = Arrays.asList(
    new Person("Alice", 20),
    new Person("Bob", 18),
    new Person("Charlie", 22)
);
Collections.sort(people);

以上就是 Comparable 接口的基本概念和用法。通过实现 Comparable 接口,我们可以定义对象的自然排序规则,使得对象可以进行比较和排序。

  • 问题 30. 请解释一下 Java 中的 Comparator 接口?

解答:Comparator 是 Java 中的一个接口,用于定义对象之间的定制排序规则。如果一个类没有实现 Comparable 接口,或者实现了但是开发者希望有其他的排序方式,那么可以使用 Comparator

Comparator 接口定义了一个 compare 方法,需要开发者进行重写。compare 方法接收两个同类型的对象作为参数,返回一个整数,有三种可能:

  • 返回 0,表示第一个参数等于第二个参数;
  • 返回正数,表示第一个参数大于第二个参数;
  • 返回负数,表示第一个参数小于第二个参数。

例如,下面的代码定义了一个 Person 类,以及一个按照年龄排序的 Comparator

代码语言:javascript复制
public class Person {
    private String name;
    private int age;

    // ... 省略构造方法和 getter、setter 方法 ...
}

public class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}

这样,我们就可以使用 AgeComparatorPerson 对象进行排序:

代码语言:javascript复制
List<Person> people = Arrays.asList(
    new Person("Alice", 20),
    new Person("Bob", 18),
    new Person("Charlie", 22)
);
Collections.sort(people, new AgeComparator());

以上就是 Comparator 接口的基本概念和用法。通过实现 Comparator 接口,我们可以定义对象的定制排序规则,使得对象可以按照我们想要的方式进行排序。

2.4、Java集合并发相关
  • 问题 31. 请解释一下 Java 中的 CopyOnWrite

解答:CopyOnWrite 是 Java 中的一种并发策略,主要应用于多线程环境下的读多写少的场景。Java 提供了 CopyOnWriteArrayListCopyOnWriteArraySet 两个线程安全的集合类,它们的实现都采用了 “写时复制”(Copy-On-Write)的策略。

“写时复制” 的基本思想是:当我们需要修改集合(如添加、删除元素)时,不直接在当前集合上进行修改,而是先将当前集合进行复制,然后在新的副本上进行修改,最后再将引用指向新的副本。这样,读操作都是在原集合上进行,不需要加锁;写操作是在副本上进行,也不会影响读操作,实现了读写分离。

“写时复制” 的优点是可以实现高并发的读操作,适合读多写少的并发场景。但是,它也有一些缺点:

  1. 内存占用:每次写操作都会复制一份新的集合,如果数据量大,会占用较多的内存。
  2. 数据一致性:读操作可能无法读取到最新的数据,因为写操作是在副本上进行的。
  3. 写操作性能:由于需要复制新的集合,所以写操作的性能会比较低。

以上就是 “写时复制” 的基本原理和特点。在使用 CopyOnWriteArrayListCopyOnWriteArraySet 时,需要根据实际的并发场景来权衡其优缺点。

  • 问题 32. 请解释一下 Java 中的 CopyOnWriteArrayList

解答:CopyOnWriteArrayList 是 Java 中的一个线程安全的 List 实现,它是通过"写时复制"(Copy-On-Write)策略来保证并发安全的。

  1. 写时复制策略:当对 CopyOnWriteArrayList 进行修改操作(如 addsetremove 等)时,它并不直接在当前数组上进行修改,而是先将当前数组进行复制,然后在新的数组上进行修改,最后再将引用指向新的数组。这样可以保证在修改过程中不会影响到读操作,实现了读写分离。
  2. 读操作无锁:由于所有的写操作都是在新的数组上进行的,所以读操作是无锁的,可以直接读取,这对于读多写少的场景性能提升很大。
  3. 写操作加锁:写操作(修改、添加、删除等)需要加锁,防止多线程同时写入时导致数据不一致。
  4. 内存占用:由于每次写操作都需要复制一个新的数组,所以 CopyOnWriteArrayList 在内存占用上会比普通的 ArrayList 大。

总的来说,CopyOnWriteArrayList 是一种适用于读多写少且需要线程安全的场景的 List 实现。但是由于写时复制策略,它在内存占用和写操作性能上有一定的开销。

  • 问题 33. 简述什么是 Fail Fast?

解答:“Fail Fast” 是 Java 集合框架中的一个错误检测机制。当多个线程对一个集合进行并发操作时,如果一个线程通过迭代器(Iterator)在遍历集合的过程中,其他线程修改了集合的结构(如添加、删除元素),那么正在遍历的线程会立即抛出 ConcurrentModificationException 异常。

“Fail Fast” 的主要目的是为了快速发现并发修改的问题,而不是等到程序运行一段时间后才发现问题。这种机制可以帮助我们尽早发现并发编程中的错误,避免出现难以预料的结果。

需要注意的是,“Fail Fast” 机制并不能保证在所有情况下都能检测到并发修改的问题,它只能尽最大可能地发现问题。另外,“Fail Fast” 机制并不是用来解决并发问题的,如果需要在多线程环境下安全地操作集合,应该使用线程安全的集合类,或者通过同步机制来保护非线程安全的集合。

  • 问题 34. 简述什么是 Fail Safe?

“Fail Safe” 是 Java 集合框架中的一种错误处理机制。在 “Fail Safe” 机制下,当一个线程正在遍历集合的过程中,其他线程对集合进行修改,不会抛出 ConcurrentModificationException 异常。

“Fail Safe” 机制的实现通常是通过创建集合的副本来实现的。当进行遍历操作时,遍历的是原集合的副本,而不是原集合。因此,对原集合的修改不会影响到遍历操作,也就不会抛出 ConcurrentModificationException 异常。

Java 中的 CopyOnWriteArrayListCopyOnWriteArraySet 就是使用了 “Fail Safe” 机制。这两个类在进行修改操作时,会创建原集合的副本,然后在副本上进行修改,最后再将引用指向新的副本。

需要注意的是,“Fail Safe” 机制虽然可以避免抛出 ConcurrentModificationException 异常,但是由于需要创建集合的副本,所以在内存占用和性能上会有一些开销。另外,由于遍历操作是在原集合的副本上进行的,所以可能无法看到其他线程对原集合的修改结果。

  • 问题 35. 请解释一下 Java 中的 ConcurrentModificationException?

解答:ConcurrentModificationException 是 Java 中的一个运行时异常,通常在多线程环境下,一个线程正在遍历集合的过程中,另一个线程修改了集合的结构(如添加、删除元素),那么正在遍历的线程可能会抛出这个异常。

这个异常通常是由 “Fail Fast” 机制引发的。“Fail Fast” 是 Java 集合框架中的一个错误检测机制,它的目的是为了尽早发现并发修改的问题,避免出现难以预料的结果。

需要注意的是,“Fail Fast” 机制并不能保证在所有情况下都能检测到并发修改的问题,它只能尽最大可能地发现问题。另外,“Fail Fast” 机制并不是用来解决并发问题的,如果需要在多线程环境下安全地操作集合,应该使用线程安全的集合类,或者通过同步机制来保护非线程安全的集合。

如果遇到 ConcurrentModificationException 异常,应该检查代码,确保在遍历集合的过程中,没有其他线程对集合进行修改。如果需要在遍历过程中修改集合,可以使用 Iteratorremove() 方法,或者使用 ListIteratoradd()set() 方法,这些方法可以安全地在遍历过程中修改集合。

2.5、Java迭代器相关
2.2、Java迭代器相关
  • 问题 36. Java 中迭代器 Iterator 是什么?

Iterator 是 Java 中的一个接口,它提供了一种统一的方式来遍历集合中的元素。Iterator 接口定义了三个方法:

  1. hasNext():检查是否还有下一个元素,如果有则返回 true,否则返回 false
  2. next():返回当前元素,并将迭代器向前移动到下一个元素。
  3. remove():删除迭代器最后一次返回的元素。这个方法是可选的,不是所有的迭代器都支持。

在 Java 的集合框架中,所有的 Collection 子类都提供了一个 iterator() 方法,用于返回一个 Iterator 对象,通过这个对象可以遍历集合中的元素。

例如,下面的代码展示了如何使用 Iterator 遍历一个 ArrayList

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
}

这就是 Iterator 的基本概念和用法。通过 Iterator,我们可以方便地遍历集合中的元素,而不需要关心集合的具体实现。

  • 问题 37. Java 中 Iterator 和 ListIterator 有什么区别?

IteratorListIterator 都是 Java 中的迭代器接口,它们都提供了遍历集合元素的方法,但是 ListIterator 提供了更多的功能。

  1. 双向遍历:Iterator 只能进行单向遍历,从前往后。而 ListIterator 支持双向遍历,既可以从前往后,也可以从后往前。ListIterator 提供了 hasPreviousprevious 方法来实现从后往前的遍历。
  2. 添加元素:ListIterator 提供了 add 方法,可以在遍历过程中添加元素,而 Iterator 不支持这个操作。
  3. 修改元素:ListIterator 提供了 set 方法,可以修改最后一次返回的元素,而 Iterator 不支持这个操作。
  4. 获取元素索引:ListIterator 提供了 nextIndexpreviousIndex 方法,可以获取下一个或上一个元素的索引,而 Iterator 不支持这个操作。
  5. 使用范围:Iterator 可以应用于所有的 Collection 子类,而 ListIterator 只能应用于 List 子类。

以上就是 IteratorListIterator 的主要区别。在需要进行更复杂的遍历操作时,可以选择使用 ListIterator

  • 问题 38. 为什么使用 Iterator 删除元素更加安全?

使用 Iterator 删除集合中的元素更加安全,主要有以下两个原因:

  1. 避免并发修改异常:在使用 for-each 循环或者普通的 for 循环遍历集合的过程中,如果直接调用集合的 remove 方法删除元素,可能会抛出 ConcurrentModificationException 异常。这是因为在遍历过程中,集合的结构发生了改变,但是这个改变并没有同步到正在进行的迭代过程中,所以会抛出异常。
  2. 避免索引问题:在使用普通的 for 循环遍历 List 的过程中,如果直接调用 Listremove 方法删除元素,可能会出现索引问题。因为删除元素后,后面的元素的索引会发生改变,可能会导致跳过某些元素或者重复处理某些元素。而使用 Iteratorremove 方法删除元素,迭代器会正确地移动到下一个元素,不会出现这个问题。

因此,推荐在遍历集合的过程中,使用 Iteratorremove 方法删除元素。

2.6、Java-8中的流处理
  • 问题 39. 如何在 Java 中使用 Java 8 的 Stream API 处理集合?

Java 8 引入了一个新的 Stream API,它提供了一种新的方式来处理集合。Stream API 可以让我们以声明式的方式处理数据,使代码更简洁,易读。

以下是一些使用 Stream API 处理集合的例子:

过滤:使用 filter() 方法可以过滤出满足条件的元素。

代码语言:javascript复制
List<String> names = Arrays.asList("John", "Jane", "Adam", "Tom");
List<String> result = names.stream()
                           .filter(name -> name.startsWith("J"))
                           .collect(Collectors.toList());

上述代码会过滤出所有以 “J” 开头的名字。

映射:使用 map() 方法可以将元素转换成其他形式。

代码语言:javascript复制
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = numbers.stream()
                               .map(n -> n * n)
                               .collect(Collectors.toList());

上述代码会将每个数字映射成它的平方。

排序:使用 sorted() 方法可以对元素进行排序。

代码语言:javascript复制
List<String> names = Arrays.asList("John", "Jane", "Adam", "Tom");
List<String> sortedNames = names.stream()
                                .sorted()
                                .collect(Collectors.toList());

上述代码会将名字按照字母顺序进行排序。

统计:使用 count()max()min()average() 等方法可以进行统计。

代码语言:javascript复制
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
long count = numbers.stream().count();
Optional<Integer> max = numbers.stream().max(Integer::compare);

上述代码会统计数字的数量和最大值。

以上就是一些使用 Stream API 处理集合的例子,Stream API 还提供了很多其他的方法,如 reduce()collect()flatMap() 等,可以满足各种复杂的数据处理需求。

  • 问题 40. 如何在 Java 中使用 Java 8 的 forEach 方法遍历集合?

解答:Java 8 在 Iterable 接口中添加了一个新的 forEach 方法,可以更简洁地遍历集合。forEach 方法接受一个 Consumer 函数式接口的实例作为参数,用于处理集合中的每个元素。

以下是使用 forEach 方法遍历集合的例子:

代码语言:javascript复制
List<String> names = Arrays.asList("John", "Jane", "Adam", "Tom");

// 使用 lambda 表达式
names.forEach(name -> System.out.println(name));

// 使用方法引用
names.forEach(System.out::println);

在上述代码中,我们使用了 lambda 表达式和方法引用两种方式来处理集合中的每个元素。这两种方式都可以使代码更简洁,易读。

需要注意的是,forEach 方法的遍历顺序并不是固定的,它取决于具体的集合实现。如果需要固定的遍历顺序,应该使用 List 或者 LinkedHashSet 等有序的集合。

0 人点赞