前端视角 Java Web 入门手册 2.4.5:集合框架——Set

254 阅读3分钟

Set 接口 是 Java 集合框架中用于存储无序且不重复元素的集合。它继承自 Collection 接口,但与 List 不同,Set 不允许存储重复的元素。Set 的主要用途包括:

  • 去重:自动确保集合中的元素唯一,适用于需要存储不重复元素的数据结构
  • 高效查找:基于哈希(HashSet)、树(TreeSet)等机制实现,提供高效的查找和存储操作
方法签名描述
boolean add(E e)将元素添加到集合中。如果元素已存在,则不添加,返回 false
boolean remove(Object o)移除集合中指定元素。如果元素存在,则移除并返回 true
boolean contains(Object o)判断集合中是否存在指定的元素
int size()返回集合中元素的数量
void clear()移除集合中的所有元素

Java 提供了多种 Set 的实现,主要有以下几种:

  1. HashSet:基于哈希表实现的 Set,具有快速的插入、查找和删除操作,但不保证元素的顺序
  2. LinkedHashSet:基于哈希表和双向链表实现的 Set,保证元素的顺序与插入顺序相同
  3. TreeSet:基于红黑树实现的 Set,保证元素按照自然顺序或指定比较器的顺序进行排序

HashSet

HashSet 是最常用的 Set 实现类,基于哈希表实现。它不保证集合迭代的顺序,特别是不保证恒定顺序

import java.util.HashSet;
import java.util.Set;

public class HashSetExample {
    public static void main(String[] args) {
        Set<String> uniqueFruits = new HashSet<>();
        uniqueFruits.add("Apple");
        uniqueFruits.add("Banana");
        uniqueFruits.add("Cherry");
        uniqueFruits.add("Apple"); // 重复元素,不会被添加
        
        System.out.println("HashSet: " + uniqueFruits); // 输出: [Apple, Banana, Cherry]
        
        // 检查是否包含元素
        boolean hasBanana = uniqueFruits.contains("Banana");
        System.out.println("是否包含 Banana: " + hasBanana); // 输出: true
        
        // 移除元素
        uniqueFruits.remove("Cherry");
        System.out.println("移除 Cherry 后: " + uniqueFruits); // 输出: [Apple, Banana]
    }
}

linkedHashSet

LinkedHashSet 是 HashSet 的子类,它通过链表维护元素的插入顺序。与 HashSet 相比,LinkedHashSet 在迭代时能保持元素的插入顺序

import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetExample {
    public static void main(String[] args) {
        Set<String> orderedFruits = new LinkedHashSet<>();
        orderedFruits.add("Apple");
        orderedFruits.add("Banana");
        orderedFruits.add("Cherry");
        orderedFruits.add("Apple"); // 重复元素,不会被添加
        
        System.out.println("LinkedHashSet: " + orderedFruits); // 输出: [Apple, Banana, Cherry]
        
        // 迭代顺序与添加顺序一致
        for (String fruit : orderedFruits) {
            System.out.println(fruit);
        }
    }
}

TreeSet

TreeSet 是 NavigableSet 接口的实现类,基于红黑树实现,能够确保元素按照其自然顺序指定的比较器顺序进行排序。TreeSet 不允许存储 null 元素

import java.util.Set;
import java.util.TreeSet;

public class TreeSetExample {
    public static void main(String[] args) {
        Set<Integer> sortedNumbers = new TreeSet<>();
        sortedNumbers.add(30);
        sortedNumbers.add(10);
        sortedNumbers.add(20);
        sortedNumbers.add(40);
        sortedNumbers.add(50);
        
        System.out.println("TreeSet: " + sortedNumbers); // 输出: [10, 20, 30, 40, 50]
        
        // 迭代顺序为排序后的顺序
        for (Integer number : sortedNumbers) {
            System.out.println(number);
        }
        
        // 使用自定义比较器(降序)
        Set<Integer> descendingSet = new TreeSet<>((a, b) -> b - a);
        descendingSet.addAll(sortedNumbers);
        System.out.println("降序 TreeSet: " + descendingSet); // 输出: [50, 40, 30, 20, 10]
    }
}

CopyOnWriteArraySet

CopyOnWriteArraySet 是 Set 接口的线程安全实现类,基于 CopyOnWriteArrayList 实现。它适用于读操作远多于写操作的场景,因为每次写操作都会复制整个底层数组。

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetExample {
    public static void main(String[] args) {
        Set<String> threadSafeSet = new CopyOnWriteArraySet<>();
        threadSafeSet.add("Apple");
        threadSafeSet.add("Banana");
        threadSafeSet.add("Cherry");
        threadSafeSet.add("Banana"); // 重复元素,不会被添加
        
        System.out.println("CopyOnWriteArraySet: " + threadSafeSet); // 输出: [Apple, Banana, Cherry]
        
        // 线程安全的迭代
        for (String fruit : threadSafeSet) {
            System.out.println(fruit);
        }
    }
}

ConcurrentSkipListSet

ConcurrentSkipListSet 是一个基于跳表(Skip List)数据结构实现的线程安全的并发有序集合。它允许在 O(logn) 的平均时间复杂度内完成插入、删除和查找操作

Set<Integer> skipListSet = new ConcurrentSkipListSet<>();
skipListSet.add(5);
skipListSet.add(2);
System.out.println(skipListSet); // [2, 5](自动排序)

Set 选择

场景推荐实现类理由
快速去重、无需顺序HashSet性能最优,时间复杂度 O(1)
去重且保留插入顺序LinkedHashSet维护插入顺序,性能接近 HashSet
元素需排序或范围查询TreeSet基于红黑树,支持有序操作
高并发读、极少写CopyOnWriteArraySet线程安全,读操作无锁
高并发有序集合ConcurrentSkipListSet线程安全,支持排序和并发访问