目录

java集合总结

java集合总结

1 ArrayList

Java ArrayList 的核心特点

  1. 动态数组结构 :自动扩容(默认1.5倍),初始容量10,适合数据量不固定的场景。
  2. 高效随机访问 :通过索引( get/set )直接操作元素,时间复杂度 O(1)
  3. 低效增删中间元素 :插入或删除元素需移动后续元素,时间复杂度 O(n)
  4. 允许重复和null :可存储重复值和 null ,灵活但需注意业务逻辑。
  5. 非线程安全 :多线程操作需手动同步(如加锁或用 Collections.synchronizedList )。

开发中的典型使用场景

  1. 动态数据缓存

    • 场景:缓存从数据库或API查询的结果集(如用户列表、商品信息)。
    • 优势:自动扩容,支持快速遍历和按索引查询。
  2. 批量数据处理

    • 场景:读取文件、解析日志后存储数据,或批量上传前的临时存储。
    • 优势:顺序添加高效,适合流式处理(如过滤、转换后存入列表)。
  3. UI层数据展示

    • 场景:前端页面渲染表格、下拉列表时,后端返回 ArrayList 格式的数据集合。
    • 优势:直接序列化为JSON,方便前端遍历。
  4. 算法中的临时存储

    • 场景:实现广度优先搜索(BFS)时用 ArrayList 模拟队列(需配合索引控制);动态规划中暂存中间结果。
    • 优势:快速随机访问,避免链表的结构开销。
  5. 数据转换与过滤

    • 场景:结合Stream API对集合进行过滤、映射、排序(如筛选出符合条件的订单)。
    • 优势:链式操作后直接生成新列表,代码简洁。
  6. 配置项管理

    • 场景:存储系统配置参数(如白名单IP、允许的文件类型)。
    • 优势:初始化后较少修改,适合高频读取。

避坑指南

  1. 避免频繁中间插入/删除 :大量增删时改用 LinkedList
  2. 预分配容量 :已知数据量大时,初始化指定容量(如 new ArrayList<>(1000) )减少扩容开销。
  3. 多线程同步 :并发环境用 CopyOnWriteArrayList 或手动加锁。
  4. 慎用 contains 方法 :判断元素是否存在时, ArrayListcontainsO(n) ,高频查询改用 HashSet

总结

  • 选 ArrayList 的场景 :数据量动态变化、高频查询、少量增删、需要快速原型开发。
  • 不选的场景 :高频在头部/中间增删、严格的内存限制(数组结构有预留空间)、线程安全要求高。

2 LinkedList

Java LinkedList 的核心特点

  1. 双向链表结构 :每个节点包含前后节点的引用,内存空间非连续,增删节点只需修改指针,无需移动数据。
  2. 高效增删头尾元素addFirst()addLast()removeFirst()removeLast() 等操作时间复杂度为 O(1)
  3. 低效随机访问 :按索引访问元素需从头或尾遍历链表,时间复杂度 O(n)
  4. 实现双端队列(Deque) :天然支持队列、栈、双端队列的操作(如 offer()poll()push()pop() )。
  5. 内存占用较高 :每个节点需额外存储前后指针,适合元素数量较少或对增删性能要求高的场景。
  6. 非线程安全 :多线程操作需手动同步。

开发中的典型使用场景

  1. 高频头尾增删操作

    • 场景:
      • 实现任务队列(如线程池任务调度)。
      • 消息中间件的临时消息缓存。
      • 操作历史记录(如撤销/重做功能,通过头插法记录操作步骤)。
    • 优势:增删头尾元素的性能远高于 ArrayList
  2. 实现栈(Stack)或队列(Queue)

    • 场景:
      • 栈:方法调用栈模拟、表达式解析(如括号匹配)。
      • 队列:广度优先搜索(BFS)中的待处理节点队列。
    • 优势:直接调用 push()pop() (栈)或 offer()poll() (队列),无需额外封装。
  3. 需要双向遍历的场景

    • 场景:
      • 音乐播放器的“上一曲/下一曲”列表。
      • 分步表单中“上一步/下一步”导航。
    • 优势:通过 ListIterator 支持双向遍历和修改。
  4. 动态调整元素顺序

    • 场景:
      • LRU缓存淘汰算法(快速将最近使用的元素移动到头部)。
      • 实时排行榜中频繁调整元素位置。
    • 优势:插入/删除中间元素时仅需修改指针,无数据搬移开销。
  5. 不确定数据量的流式处理

    • 场景:
      • 逐行读取大文件并动态处理(如日志分析)。
      • 网络流数据的临时缓冲(如分片上传)。
    • 优势:链表动态扩展无扩容成本,避免 ArrayList 的扩容数组拷贝。
  6. 内存敏感但增删频繁的小数据集

    • 场景:
      • 高频增删的小型配置项集合(如动态路由规则)。
      • 临时存储中间计算结果(如递归算法的路径记录)。
    • 优势:小数据量下链表的内存劣势不明显,且增删性能更优。

避坑指南

  1. 避免按索引遍历 :优先用 Iteratorforeach ,避免低效的 get(index)
  2. 慎用中间插入/删除 :虽然链表增删节点快,但定位到中间位置仍需 O(n) 时间。
  3. 多线程同步 :使用 Collections.synchronizedList() 或改用 ConcurrentLinkedQueue
  4. 注意内存开销 :存储海量数据时,链表的指针内存可能成为瓶颈,优先考虑 ArrayList

总结

  • 选 LinkedList 的场景 :高频头尾增删、需实现队列/栈、双向遍历、动态调整顺序、小规模数据流处理。
  • 不选的场景 :高频随机访问、海量数据存储、内存严格受限、需要连续内存的场景(如缓存友好型算法)。

对比 ArrayList

  • 增删性能LinkedList 在头尾增删占优, ArrayList 在尾部增删占优。
  • 访问性能ArrayList 的随机访问效率碾压 LinkedList
  • 内存占用ArrayList 内存紧凑, LinkedList 因指针占用额外空间。

3 Vector

Java Vector 的核心特点

  1. 线程安全 :所有方法均用 synchronized 修饰,支持多线程并发读写(但性能较低)。
  2. 动态数组结构 :底层基于数组实现,自动扩容(默认容量翻倍,如 10 → 20 → 40)。
  3. 遗留类 :早期 Java 集合的实现(JDK 1.0),现多被 ArrayList 或并发集合(如 CopyOnWriteArrayList )取代。
  4. 枚举遍历 :提供 elements() 方法返回 Enumeration 对象(类似 Iterator 的前身)。
  5. 同步开销大 :所有操作加锁,单线程环境下性能显著低于 ArrayList

开发中的典型使用场景

  1. 多线程环境下的共享数据存储

    • 场景:多个线程需要同时读写同一列表(如全局配置参数表)。
    • 注意:即使 Vector 线程安全,复合操作(如“检查再更新”)仍需额外同步。
  2. 历史遗留系统维护

    • 场景:维护早期 Java 版本(如 JDK 1.2 之前)的代码库时,需兼容 Vector 的 API。
  3. 需要同步的动态数组

    • 场景:简单的多线程任务队列(如生产者-消费者模型),但性能要求不高。
  4. 替代 Stack 类

    • 场景: Stack 类继承自 Vector ,但已不推荐使用;若需线程安全的栈,可用 VectoraddElement()removeElement() 模拟栈操作。
  5. 同步枚举遍历

    • 场景:通过 elements() 方法获取 Enumeration 遍历集合(需在遍历过程中同步)。

避坑指南

  1. 避免在单线程中使用 :优先选择 ArrayList (性能更高)。
  2. 慎用复合操作 :即使单个方法线程安全,组合操作(如 if (!vec.isEmpty()) vec.remove(0) )仍需外部同步。
  3. 替代方案
    • 高并发读:用 CopyOnWriteArrayList
    • 高并发写:用 ConcurrentLinkedQueueConcurrentHashMap
    • 简单同步需求:用 Collections.synchronizedList(new ArrayList<>())
  4. 内存浪费风险 :容量翻倍扩容可能导致内存冗余,可初始化时指定容量(如 new Vector<>(100) )。

总结

  • 选 Vector 的场景 :兼容旧代码、简单的多线程共享数据、需同步且对性能不敏感的场景。
  • 不选的场景 :高并发写、单线程环境、内存敏感、需要高性能随机访问。

对比 ArrayList/LinkedList

  • 线程安全Vector 自带同步, ArrayList/LinkedList 需外部控制。
  • 性能Vector 的同步机制导致性能远低于 ArrayList
  • 扩容策略Vector 容量翻倍, ArrayList 扩容 1.5 倍,内存利用更高效。

现代替代方案

  • 需线程安全的动态数组: Collections.synchronizedList() + ArrayList
  • 高并发场景: CopyOnWriteArrayList (读多写少)或 ConcurrentLinkedQueue (写多读少)。

4 HashSet


Java HashSet 的核心特点

  1. 基于哈希表实现 :底层依赖 HashMap ,利用哈希值快速定位元素,查找/插入/删除的平均时间复杂度为 O(1)
  2. 元素唯一性 :通过 equals()hashCode() 方法保证元素不重复。
  3. 无序性 :不保证元素的存储顺序(与插入顺序无关),迭代顺序可能随机变化。
  4. 允许 null :可存储一个 null 元素。
  5. 非线程安全 :多线程操作需手动同步(如 Collections.synchronizedSet() )。
  6. 性能依赖哈希函数 :哈希冲突过多时,性能退化为 O(n)

开发中的典型使用场景

  1. 快速去重

    • 场景:
      • 从数据库或文件中提取数据后,过滤重复记录(如用户ID、订单号)。
      • 统计日志中独立IP地址或唯一用户访问量。
    • 优势:去重操作时间复杂度低,代码简洁。
  2. 集合运算

    • 场景:
      • 判断两个数据集是否有交集(如用户权限校验)。
      • 合并多个来源的数据并去重(如多平台订单汇总)。
    • 优势:直接调用 addAll() (并集)、 retainAll() (交集)、 removeAll() (差集)等方法。
  3. 快速存在性检查

    • 场景:
      • 缓存校验黑名单(如敏感词、禁止访问的IP)。
      • 用户注册时检查用户名是否已被占用。
    • 优势: contains() 方法性能远高于 List 的遍历查找。
  4. 临时唯一性存储

    • 场景:
      • 遍历树或图时记录已访问的节点(避免重复处理)。
      • 分布式任务调度中标记已处理的任务ID。
    • 优势:轻量且无需维护顺序。
  5. 标签或属性管理

    • 场景:
      • 商品的多标签分类(如“电子产品”“促销品”),确保标签唯一。
      • 用户兴趣标签的存储与快速匹配。
    • 优势:天然支持唯一性,避免重复标签污染数据。
  6. 数据清洗与预处理

    • 场景:
      • 清洗爬虫抓取的网页URL,避免重复爬取。
      • 预处理数据集中的异常值或重复条目。
    • 优势:去重效率高,适合大规模数据处理。

避坑指南

  1. 重写 hashCode()equals() :存储自定义对象时,必须正确重写这两个方法,否则无法保证唯一性。
  2. 避免存储可变对象 :若对象哈希值随内容变化,可能导致 HashSet 中元素“丢失”。
  3. 初始化容量与负载因子 :数据量较大时,指定初始容量和负载因子(如 new HashSet<>(1000, 0.75f) ),减少扩容次数。
  4. 线程安全替代方案 :多线程环境用 ConcurrentHashMap.newKeySet()CopyOnWriteArraySet
  5. 慎用大规模数据 :哈希表内存占用较高,超大规模数据去重可改用布隆过滤器(Bloom Filter)。

总结

  • 选 HashSet 的场景 :高频去重、快速存在性检查、无需顺序的集合运算、临时唯一性存储。
  • 不选的场景 :需要元素有序(用 LinkedHashSetTreeSet )、需要按范围查询(用 TreeSet )、内存极度敏感(用位图或数组)。

对比其他 Set 实现

  • TreeSet :基于红黑树,元素按自然顺序或自定义规则排序,查找/插入/删除时间复杂度 O(log n)
  • LinkedHashSet :维护插入顺序的链表,适合需要按顺序迭代且去重的场景。

性能关键点

  • 哈希函数的质量直接影响冲突概率,设计差的对象哈希方法会显著降低性能。
  • 负载因子默认 0.75,表示哈希表填充 75% 后触发扩容,可根据场景调整(值越小,冲突越少,内存占用越高)。

5 TreeSet

Java TreeSet 的核心特点

  1. 基于红黑树实现 :元素按自然顺序或自定义规则排序,插入时自动维护有序性。
  2. 元素唯一且有序 :通过 compareTo()Comparator 保证唯一性,迭代时按升序或自定义顺序输出。
  3. 操作效率稳定 :查找、插入、删除操作的时间复杂度为 O(log n) ,适合需要动态维护有序集合的场景。
  4. 不允许 null (自然排序模式下):若未指定自定义 Comparator ,插入 null 会抛出 NullPointerException
  5. 非线程安全 :多线程操作需手动同步(如 Collections.synchronizedSortedSet() )。

开发中的典型使用场景

  1. 动态排序数据集

    • 场景:
      • 实时排行榜(如游戏玩家积分榜、电商商品销量榜),插入数据时自动排序。
      • 股票价格实时更新后按价格排序展示。
    • 优势:无需手动调用排序方法,维护成本低。
  2. 范围查询与过滤

    • 场景:
      • 查询某区间内的数据(如筛选考试分数在 80~100 分的学生)。
      • 统计日志中某时间段内的请求记录(通过 subSet()headSet()tailSet() 方法)。
    • 优势:基于红黑树结构,范围查询效率远高于遍历无序集合。
  3. 去重且有序存储

    • 场景:
      • 从异构数据源合并数据后,按时间戳或优先级去重并排序。
      • 用户操作日志按时间顺序存储,避免重复记录。
    • 优势:同时满足唯一性和有序性需求。
  4. 任务调度与优先级管理

    • 场景:
      • 定时任务队列按执行时间排序(如延迟任务调度)。
      • 线程池中任务按优先级(高/中/低)动态调整执行顺序。
    • 优势:自动按规则调整顺序,确保高优先级任务优先处理。
  5. 字典序或分类管理

    • 场景:
      • 实现自动补全功能(如搜索框提示词按字母顺序排序)。
      • 文件系统中目录项按名称排序展示。
    • 优势:天然支持字典序,简化业务逻辑。
  6. 复杂规则去重

    • 场景:
      • 根据自定义业务规则(如“用户ID+日期”组合)去重。
      • 订单去重时需忽略大小写或特定字段差异。
    • 优势:通过自定义 Comparator 灵活定义唯一性规则。

避坑指南

  1. 正确实现比较逻辑

    • 存储自定义对象时,需实现 Comparable 接口或提供 Comparator ,否则抛出 ClassCastException
    • 比较逻辑需与 equals() 一致,避免破坏唯一性规则(如两个对象 compareTo() 返回 0,但 equals()false )。
  2. 慎用可变对象

    • 若对象的排序字段被修改,可能导致 TreeSet 内部顺序混乱,需先删除对象再重新插入。
  3. 性能敏感场景慎用

    • 高频插入/删除时,红黑树的旋转操作可能成为性能瓶颈,可改用 HashSet
      • 手动排序。
  4. 替代方案

    • 需要线程安全:使用 ConcurrentSkipListSet
    • 仅需插入顺序:使用 LinkedHashSet
    • 内存敏感:权衡红黑树的结构开销与查询效率。

总结

  • 选 TreeSet 的场景 :需动态维护有序集合、高频范围查询、自定义排序规则、去重且排序。
  • 不选的场景 :仅需去重无需排序(用 HashSet )、高频随机访问(用 ArrayList )、内存极度受限。

对比其他 Set 实现

  • HashSet :无序,去重效率 O(1) ,适合纯去重场景。
  • LinkedHashSet :维护插入顺序,适合需要按插入顺序迭代的去重场景。
  • ConcurrentSkipListSet :线程安全且有序,适合高并发排序需求。

性能关键点

  • 数据量较小时, TreeSet 的有序性优势明显;数据量极大时需权衡红黑树的维护成本。
  • 自定义 Comparator 的复杂度直接影响操作效率,需避免复杂计算逻辑。

6 HashMap

Java HashMap 的核心特点

  1. 基于哈希表实现 :底层是“数组+链表/红黑树”(JDK8+),通过哈希值快速定位桶位置,理想情况下操作时间复杂度为 O(1)
  2. 键值对存储 :唯一键(通过 equals()hashCode() 去重),允许一个 null 键和多个 null 值。
  3. 非线程安全 :多线程并发修改可能触发无限循环或数据丢失(JDK7)或脏读(JDK8+)。
  4. 动态扩容 :默认容量 16,负载因子 0.75,容量超过阈值时扩容 2 倍并重新哈希。
  5. 哈希冲突管理 :链表长度超过 8 时转红黑树(提升查询效率),长度小于 6 时退化为链表。

开发中的典型使用场景

  1. 缓存系统

    • 场景:
      • 临时存储高频访问数据(如用户会话信息、热点商品详情)。
      • 本地缓存数据库查询结果(键为查询条件,值为结果集)。
    • 优势:快速通过键查找值,避免重复计算或数据库访问。
  2. 数据索引与映射

    • 场景:
      • 建立对象关联(如用户ID映射用户详情、订单号映射物流状态)。
      • 文件路径与文件内容的快速映射(如配置文件解析)。
    • 优势:直接通过键定位数据,无需遍历。
  3. 分组与统计

    • 场景:
      • 统计词频(如文本中每个单词的出现次数)。
      • 按属性分组数据(如按部门分类员工、按城市归类订单)。
    • 优势:键作为分类标识,值存储统计结果或子集合。
  4. 配置参数管理

    • 场景:
      • 存储系统动态配置(如开关参数、API地址映射)。
      • 国际化资源文件加载(键为文案ID,值为多语言文本)。
    • 优势:灵活增删配置项,支持快速读取。
  5. 分布式分片

    • 场景:
      • 按哈希值分配任务到不同节点(如用户ID分片路由)。
      • 数据库分库分表时,用键计算数据所属分片。
    • 优势:哈希算法均匀分布数据,减少热点问题。
  6. 对象属性动态扩展

    • 场景:
      • 为实体附加临时元数据(如请求上下文的附加参数)。
      • 动态表单字段存储(键为字段名,值为用户输入)。
    • 优势:无需预定义结构,灵活扩展键值对。

避坑指南

  1. 线程安全替代方案

    • 多线程读写用 ConcurrentHashMap
    • 多线程读多写少用 Collections.synchronizedMap() 包装。
  2. 优化哈希函数

    • 自定义对象作为键时,需正确重写 hashCode()equals() ,避免哈希冲突。
  3. 合理初始化容量

    • 预估数据量时指定初始容量(如 new HashMap<>(1000) ),减少扩容开销。
  4. 避免遍历时修改

    • 使用 Iterator 遍历时删除元素,防止 ConcurrentModificationException
  5. 慎用可变对象作为键

    • 若键对象哈希值变化,会导致数据“丢失”(无法通过 get() 找到原有条目)。
  6. 处理哈希碰撞

    • 高频冲突时,考虑调整哈希算法或改用 LinkedHashMap (维护插入顺序)。

总结

  • 选 HashMap 的场景 :高频键值查询、去重映射、动态配置、缓存、分组统计、哈希分片。
  • 不选的场景 :需要有序遍历(用 LinkedHashMapTreeMap )、高并发写(用 ConcurrentHashMap )、范围查询(用 TreeMap )。

对比其他 Map 实现

  • Hashtable :遗留类,全方法同步,性能低,不推荐使用。
  • TreeMap :基于红黑树,按键自然顺序或自定义顺序排序,操作效率 O(log n)
  • LinkedHashMap :维护插入顺序或访问顺序,适合缓存淘汰策略(如LRU)。

性能关键点

  • 哈希函数的质量直接影响冲突率,设计差的哈希函数会导致性能退化为 O(n)
  • 负载因子默认 0.75,表示哈希表填充 75% 后扩容,可根据场景调整(值越小,冲突概率越低,但内存占用更高)。

7 TreeMap

Java TreeMap 的核心特点

  1. 基于红黑树实现 :键值对按键的自然顺序( Comparable )或自定义 Comparator 排序,保证有序性。
  2. 键唯一且有序 :迭代时按键的升序或自定义顺序输出,支持范围查询(如子映射、头部/尾部映射)。
  3. 操作效率稳定 :查找、插入、删除操作的时间复杂度为 O(log n) ,适合需要动态维护有序键值对的场景。
  4. 不允许 null (自然排序模式下):若未指定自定义 Comparator ,插入 null 键会抛出 NullPointerException
  5. 非线程安全 :多线程操作需手动同步(如 Collections.synchronizedSortedMap() )。

开发中的典型使用场景

  1. 动态排序键值对

    • 场景:
      • 实时排行榜(如玩家积分按分数排序、商品按价格排序)。
      • 日志按时间戳排序存储(键为时间戳,值为日志内容)。
    • 优势:自动维护键的有序性,无需手动排序。
  2. 范围查询与区间操作

    • 场景:
      • 查询某时间段内的数据(如订单在 2023-01-01 至 2023-06-30 的记录)。
      • 筛选价格区间内的商品(如 100~500 元)。
    • 优势:通过 subMap()headMap()tailMap() 快速获取子映射。
  3. 字典序或分类管理

    • 场景:
      • 实现搜索提示词(如按字母顺序存储关键词)。
      • 多语言资源文件按键的字母顺序加载(如国际化文案)。
    • 优势:天然支持字典序,简化排序逻辑。
  4. 带权重的优先级调度

    • 场景:
      • 任务队列按优先级排序(如高、中、低优先级的后台任务)。
      • 定时任务按触发时间排序(键为执行时间,值为任务对象)。
    • 优势:按键顺序处理任务,确保优先级规则。
  5. 复杂键的排序与去重

    • 场景:
      • 按组合键排序(如“用户ID+操作时间”作为复合键)。
      • 去重并排序异构数据(如合并多个数据源的记录)。
    • 优势:通过自定义 Comparator 灵活定义排序规则。
  6. 统计与聚合分析

    • 场景:
      • 统计区间数据分布(如按分数段统计学生人数)。
      • 实时聚合时间窗口内的指标(如每分钟请求量)。
    • 优势:基于有序键快速定位区间并聚合结果。

避坑指南

  1. 正确实现比较逻辑

    • 自定义键对象需实现 Comparable 或提供 Comparator ,否则抛出 ClassCastException
    • 比较逻辑需与 equals() 一致,避免键唯一性冲突。
  2. 慎用可变键对象

    • 若键的排序字段被修改,会导致 TreeMap 内部顺序混乱,需先删除再重新插入。
  3. 替代方案

    • 需要线程安全:使用 ConcurrentSkipListMap
    • 仅需插入顺序:使用 LinkedHashMap
    • 无需排序且高频查询:使用 HashMap
  4. 性能敏感场景优化

    • 高频插入/删除时,红黑树的平衡操作可能成为瓶颈,可改用 HashMap
      • 定期排序。

总结

  • 选 TreeMap 的场景 :需要键有序、高频范围查询、动态排序、复杂键规则、优先级调度。
  • 不选的场景 :仅需快速存取无序数据(用 HashMap )、内存极度受限、高并发写(用 ConcurrentSkipListMap )。

对比其他 Map 实现

  • HashMap :无序,操作效率 O(1) ,适合纯键值存取。
  • LinkedHashMap :维护插入或访问顺序,适合缓存淘汰策略(如LRU)。
  • ConcurrentSkipListMap :线程安全且有序,适合高并发排序需求。

性能关键点

  • 数据量较小时, TreeMap 的有序性优势明显;数据量极大时需权衡红黑树的维护成本。
  • 自定义 Comparator 的逻辑复杂度直接影响操作效率,需避免复杂计算。