单列集合Collection接口

Collection接口

  • Collection 是 Java 集合框架中的一个核心接口,位于 java.util 包中。它是所有单列集合(即存储单个元素的集合)的根接口,提供了对集合进行基本操作的方法。

定义的通用方法

  1. 添加元素

    • boolean add(E e)向集合中添加一个元素,元素成功添加返回 true,反之返回false

      Collection<String> collection = new ArrayList<>();
      collection.add("Apple"); // 返回 true
      collection.add("Apple"); // 如果集合不允许重复元素,返回 false
      
    • boolean addAll(Collection<? extends E> c),将指定集合中的所有元素添加到当前集合中,如果当前集合因调用此方法而发生变化 true,如果指定集合为空或所有元素都已存在于当前集合中返回false

      Collection<String> collection1 = new ArrayList<>();
      collection1.add("Apple");
      collection1.add("Banana");
      
      Collection<String> collection2 = new ArrayList<>();
      collection2.add("Cherry");
      collection2.add("Banana");
      
      collection1.addAll(collection2); // 返回 true,collection1 现在包含 ["Apple", "Banana", "Cherry"]
      
  2. 删除元素

    • boolean remove(Object o)从集合中移除指定的元素,如果集合包含该元素并成功移除,返回 true,如果集合不包含该元素,返回 false

      Collection<String> collection = new ArrayList<>();
      collection.add("Apple");
      collection.add("Banana");
      
      collection.remove("Apple"); // 返回 true
      collection.remove("Cherry"); // 返回 false
      
    • boolean removeAll(Collection<?> c)从当前集合中移除所有包含在指定集合中的元素,如果当前集合因调用此方法而发生变化,返回 true,如果当前集合未发生变化,返回 false

      Collection<String> collection1 = new ArrayList<>();
      collection1.add("Apple");
      collection1.add("Banana");
      collection1.add("Cherry");
      
      Collection<String> collection2 = new ArrayList<>();
      collection2.add("Apple");
      collection2.add("Cherry");
      
      collection1.removeAll(collection2); // 返回 true,collection1 现在只包含 ["Banana"]
      
    • boolean retainAll(Collection<?> c)仅保留当前集合中那些也包含在指定集合中的元素(即求交集),变化为true,反之为false

      Collection<String> collection1 = new ArrayList<>();
      collection1.add("Apple");
      collection1.add("Banana");
      collection1.add("Cherry");
      
      Collection<String> collection2 = new ArrayList<>();
      collection2.add("Apple");
      collection2.add("Cherry");
      
      collection1.retainAll(collection2); // 返回 true,collection1 现在只包含 ["Apple", "Cherry"]
      
    • void clear()移除集合中的所有元素,清空集合

      Collection<String> collection = new ArrayList<>();
      collection.add("Apple");
      collection.add("Banana");
      
      collection.clear(); // 清空集合,collection 现在为空
      
  3. 查询操作

    • boolean contains(Object o)判断集合中是否包含指定的元素,如果集合包含该元素,返回 true

      Collection<String> collection = new ArrayList<>();
      collection.add("Apple");
      
      System.out.println(collection.contains("Apple")); // 输出 true
      System.out.println(collection.contains("Banana")); // 输出 false
      
    • boolean containsAll(Collection<?> c)判断集合中是否包含指定集合中的所有元素,如果集合包含指定集合中的所有元素,返回 true

      Collection<String> collection1 = new ArrayList<>();
      collection1.add("Apple");
      collection1.add("Banana");
      
      Collection<String> collection2 = new ArrayList<>();
      collection2.add("Apple");
      
      System.out.println(collection1.containsAll(collection2)); // 输出 true
      
    • boolean isEmpty()判断集合是否为空,如果集合中没有元素,返回 true

      Collection<String> collection = new ArrayList<>();
      System.out.println(collection.isEmpty()); // 输出 true
      
      collection.add("Apple");
      System.out.println(collection.isEmpty()); // 输出 false
      
    • int size()返回集合中的元素数量

      Collection<String> collection = new ArrayList<>();
      collection.add("Apple");
      collection.add("Banana");
      
      System.out.println(collection.size()); // 输出 2
      
  4. 集合转换

    • Object[] toArray()将集合转换为一个数组,数组中的元素是集合中的所有元素

      Collection<String> collection = new ArrayList<>();
      collection.add("Apple");
      collection.add("Banana");
      
      Object[] array = collection.toArray();
      System.out.println(Arrays.toString(array)); // 输出 [Apple, Banana]
      

迭代器

  • iterator() 是 Collection 接口中的一个重要方法,用于返回一个 迭代器(Iterator) 对象。迭代器是 Java 集合框架中用于遍历集合元素的工具,它提供了一种统一的方式来访问集合中的元素,而不需要关心集合的具体实现

  • iterator() 方法返回的是一个实现了 Iterator 接口的对象。Iterator 接口定义了以下三个核心方法

    1. boolean hasNext():判断集合中是否还有下一个元素,如果集合中还有未遍历的元素,返回 true

    2. E next():返回集合中的下一个元素,并将迭代器的指针向后移动一位返回值:集合中的下一个元素

      • 如果集合中没有更多元素(即 hasNext() 返回 false),调用 next() 会抛出 NoSuchElementException
    3. void remove():从集合中移除迭代器最后一次返回的元素(即最近一次调用 next() 返回的元素)

      • 每次调用 next() 后只能调用一次 remove(),否则会抛出 IllegalStateException
      • 如果集合不支持移除操作,调用 remove() 会抛出 UnsupportedOperationException

Iterator 的工作机制

  • 迭代器内部维护一个指针(或游标),初始时指向集合的第一个元素之前的位置。

  • 每次调用 next(),指针会向后移动一位,并返回当前指向的元素。

  • hasNext() 用于判断指针是否已经到达集合的末尾。

  • remove() 会移除最后一次 next() 返回的元素

使用 Iterator 遍历集合的步骤

  1. 调用集合的 iterator() 方法获取迭代器对象。

  2. 使用 hasNext() 检查是否还有元素。

  3. 使用 next() 获取下一个元素。

  4. (可选)使用 remove() 移除元素

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

public class IteratorExample {
    public static void main(String[] args) {
        // 创建一个 ArrayList 集合
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");
        list.add("Date");

        // 获取迭代器
        Iterator<String> iterator = list.iterator();

        // 遍历集合
        System.out.println("遍历集合:");
        while (iterator.hasNext()) {
            String item = iterator.next(); // 获取下一个元素
            System.out.println("当前元素:" + item);

            // 如果元素是 "Banana",则移除
            if (item.equals("Banana")) {
                iterator.remove(); // 移除最后一次 next() 返回的元素
                System.out.println("已移除元素:Banana");
            }
        }

        // 输出修改后的集合
        System.out.println("\n修改后的集合:");
        for (String item : list) {
            System.out.println(item);
        }
    }
}

迭代器的优点

  • 通用性:Iterator 可以用于遍历任何实现了 Collection 接口的集合类(如 ArrayList、HashSet、LinkedList 等)。

  • 安全性:在遍历过程中,如果集合被修改(非通过迭代器自身的 remove() 方法),迭代器会抛出 ConcurrentModificationException,从而避免数据不一致的问题。

  • 灵活性:Iterator 提供了 remove() 方法,可以在遍历时安全地移除元素

迭代器的注意点

  • 单向遍历:Iterator 只能向前遍历,不能后退。

  • 一次性使用:一个迭代器对象只能遍历集合一次。如果需要重新遍历,必须重新获取迭代器。

  • 并发修改:在遍历过程中,如果直接通过集合的方法(如 add()、remove())修改集合,会抛出 ConcurrentModificationException。如果需要修改集合,应使用迭代器的 remove() 方法。

增强for循环

  • 增强 for 循环(for-each 循环)是 Java 5 引入的语法糖,底层实际使用的是 Iterator

    for (String item : collection) {
        System.out.println(item);
    }
    //等价于
    Iterator<String> iterator = collection.iterator();
    while (iterator.hasNext()) {
        String item = iterator.next();
        System.out.println(item);
    }
    

迭代器的并发修改问题

  • 在 Java 集合框架中,许多集合类(如 ArrayList、HashSet 等)都是 非线程安全 的。这些集合类内部维护了一个 修改计数器(modCount),用于记录集合被修改的次数(如添加、删除元素)

  • 当使用 Iterator 遍历集合时,迭代器会在初始化时记录当前的 modCount 值。在遍历过程中,每次调用迭代器的 next() 或 remove() 时,迭代器会检查集合的 modCount 是否与初始化时记录的 modCount 一致。如果不一致,说明集合在遍历过程中被外部修改(非通过迭代器自身的方法),此时迭代器会抛出 ConcurrentModificationException

  • ConcurrentModificationException 是一种 快速失败(fail-fast) 机制,旨在提醒开发者集合在遍历过程中被意外修改,可能导致数据不一致或不可预期的行为

  • 只有添加和删除操作会触发 ConcurrentModificationException,而修改操作(如 list.set())通常不会触发该异常

  • ConcurrentModificationException 的触发条件是 结构性修改(structural modification),即改变集合的大小(如添加或删除元素)

  • list.set() 只是修改了集合中某个元素的值,并没有改变集合的大小,因此不会触发 ConcurrentModificationException

    List<String> list = new ArrayList<>();
    list.add("A");
    list.add("B");
    list.add("C");
    list.add("D");
    
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String item = iterator.next();
        if (item.equals("B")) {
            // 直接通过集合的 remove() 方法修改集合
            //这里需要注意如果list的集合没有添加字符D则不会报错,因为iterator.hasNext()为false会结束程序而不会进行检测
            //如果list的集合添加了字符D,则会执行到next()方法进行检测,则报错
            list.remove(item);  
        }
    }
    
    1. 使用 Iterator 遍历 ArrayList。

    2. 当遍历到元素 "B" 时,直接调用 list.remove(item) 修改集合。

    3. 由于集合的 modCount 发生了变化,而迭代器记录的 modCount 未更新,因此在下一次调用 iterator.next() 时,会抛出 ConcurrentModificationException

  • 快速失败机制主要是为了检测在迭代过程中对 集合 结构的修改(如添加或删除值),而不是对已有值的修改,因为没有改动修改计数器(modCount)

    List<Person> list = new ArrayList<>();
    	list.add(new Person(1));
    	list.add(new Person(2));
    	list.add(new Person(3));
    
    Iterator<Person> iterator = list.iterator();
    while (iterator.hasNext()) {
        Person item = iterator.next();
        if (item.id==2) {
            item.setId(20); // 可以修改已有值
        }
    }
    
  • 为了避免 ConcurrentModificationException,在遍历集合时,如果需要修改集合,应使用迭代器自身的 remove() 方法,而不是直接通过集合的方法修改

    List<String> list = new ArrayList<>();
    list.add("A");
    list.add("B");
    list.add("C");
    
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String item = iterator.next();
        if (item.equals("B")) {
            iterator.remove(); // 使用迭代器的 remove() 方法
        }
    }
    
    1. 每次调用 next() 后只能调用一次 remove():如果在调用 remove() 之前没有调用 next(),或者多次调用 remove(),会抛出 IllegalStateException
    2. 不支持添加操作:Iterator 只提供了 remove() 方法,不支持添加元素。如果需要添加元素,可以考虑使用 ListIterator(它是 Iterator 的子接口,支持添加和修改操作)
  • 如果需要在遍历过程中频繁修改集合,可以考虑以下替代方案

    1. 使用 ListIterator,ListIterator 是 Iterator 的增强版,支持在遍历过程中添加、修改和删除元素

      注意Collection 接口中只提供了 Iterator,ListIterator 是 List 特有的功能,适用于有序集合

      List<String> list = new ArrayList<>();
      list.add("A");
      list.add("B");
      list.add("C");
      
      ListIterator<String> listIterator = list.listIterator();
      while (listIterator.hasNext()) {
          String item = listIterator.next();
          if (item.equals("B")) {
              listIterator.remove(); // 删除元素
              listIterator.add("D"); // 添加元素
          }
      }
      
    2. 使用 CopyOnWriteArrayList

      • CopyOnWriteArrayList 是线程安全的集合类,它在修改集合时会创建一个新的副本,因此不会抛出 ConcurrentModificationException

      • List<String> list = new CopyOnWriteArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        
        for (String item : list) {
            if (item.equals("B")) {
                list.remove(item); // 直接修改集合
            }
        }
        
    3. 使用普通 for 循环,如果需要通过索引修改集合,可以使用普通 for 循环

      List<String> list = new ArrayList<>();
      list.add("A");
      list.add("B");
      list.add("C");
      
      for (int i = 0; i < list.size(); i++) {
          String item = list.get(i);
          if (item.equals("B")) {
              list.remove(i); // 直接通过索引修改集合
              i--; // 调整索引
          }
      }
      

方法总结

Collection 接口提供了对集合进行添加、删除、查询、遍历和转换的通用方法。这些方法是所有单列集合类的基础,适用于 List、Set、Queue 等集合类型。

1. 添加元素

  • add(E e):向集合中添加一个元素。成功添加返回 true,否则返回 false。
  • addAll(Collection<? extends E> c):将指定集合中的所有元素添加到当前集合中。集合发生变化返回 true,否则返回 false。

2. 删除元素

  • remove(Object o):移除集合中的指定元素。成功移除返回 true,否则返回 false。
  • removeAll(Collection<?> c):移除当前集合中所有包含在指定集合中的元素。集合发生变化返回 true,否则返回 false。
  • retainAll(Collection<?> c):仅保留当前集合中那些也包含在指定集合中的元素(求交集)。集合发生变化返回 true,否则返回 false。
  • clear():清空集合中的所有元素。

3. 查询操作

  • contains(Object o):判断集合是否包含指定元素。包含返回 true,否则返回 false。
  • containsAll(Collection<?> c):判断集合是否包含指定集合中的所有元素。包含返回 true,否则返回 false。
  • isEmpty():判断集合是否为空。为空返回 true,否则返回 false。
  • size():返回集合中的元素数量。

4. 集合转换

  • toArray():将集合转换为一个 Object 数组。
  • toArray(T[] a):将集合转换为指定类型的数组。

5. 遍历集合

  • iterator():返回一个用于遍历集合中元素的迭代器。
posted @ 2025-03-03 21:56  QAQ001  阅读(35)  评论(0)    收藏  举报