Java 集合框架

本文首发于公众号:JavaArchJourney

Java集合框架

Java 集合框架是提供了一套设计优良、易于使用和扩展的接口和类,用于存储和操作一组对象。集合框架位于java.util包中,它提供了丰富的功能来处理数据集合,包括列表( List )、集合( Set )、队列( Queue )、映射( Map )等。

  • Collection:这是集合层次结构中的根接口。它包含了用于添加、移除和搜索元素的方法。
  • List:继承自 Collection 接口,是一个有序的集合,允许包含重复元素。支持通过索引来访问元素。
    • 实现类包括 ArrayListLinkedListVector 等。
  • Set:也是一个继承自 Collection 接口的集合类型,但不允许包含重复元素。
    • 常见实现类有 HashSetLinkedHashSetTreeSet
  • Queue:通常用于实现 FIFO (先进先出)的数据结构,但也有其他变种如优先队列。
    • 优先级队列 PriorityQueue 是一个典型的实现。
  • Map:不是 Collection 接口的子接口,它存储键值对。Map 不能包含重复的键;每个键最多只能映射到一个值。
    • 常见实现类有 HashMapLinkedHashMapTreeMap

Collection接口

Collection接口关系:

List接口实现类介绍

List 表示一个有序的、允许重复元素的集合,并且可以通过索引(位置)来访问和操作其中的元素。

常用方法:

  • add(E element):在列表末尾添加一个元素。
  • add(int index, E element):在指定索引处插入一个元素。
  • get(int index):返回指定索引处的元素。
  • set(int index, E element):替换指定索引处的元素。
  • remove(int index):删除指定索引处的元素。
  • size():返回列表中的元素个数。
  • indexOf(Object o):返回指定元素首次出现的索引,不存在则返回 -1。
  • lastIndexOf(Object o):返回指定元素最后一次出现的索引。
  • subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 的子列表。

List接口的常见实现类:

  • ArrayList:基于动态数组实现。更多阅读:ArrayList源码分析。
  • LinkedList:基于双向链表实现。更多阅读:LinkedList源码分析。
  • ArrayList LinkedList对比如下:
特性/类别 ArrayList LinkedList
数据结构 动态数组 双向链表
随机访问性能 快(O(1)) 慢(O(n),需遍历查找)
插入/删除头部 慢(O(n),需移动元素) 快(O(1),只需修改头节点指针)
插入/删除尾部 快(O(1),如果无需扩容) 快(O(1),只需修改尾节点指针)
插入/删除中间 慢(O(n),需移动元素) 较快(O(n),但不涉及元素移动,仅修改指针)
内存占用 因为是连续存储,所以内存使用较为紧凑 需要额外的空间存储指向前后的引用,内存开销较大
线程安全性 不是线程安全 不是线程安全
实现接口 List, RandomAccess List, Deque
适用场景 高效的随机访问,较少的插入和删除操作 高效的插入和删除操作,尤其是列表两端
  • Vector旧类,不建议使用 ):类似于 ArrayList ,但它是一个同步(线程安全)的集合,它的所有的方法都被隐式地同步了(所有方法 synchronized ),这使得 Vector 可以在多线程环境中安全使用。然而,由于同步带来的额外开销,使用这个类可能会导致性能下降。通常推荐在单线程环境下使用 ArrayList ;在多线程并发场景下,使用Collections.synchronizedList(new ArrayList<>());来创建一个线程安全的列表,或者直接使用并发集合如 CopyOnWriteArrayList
  • Stack旧类,不建议使用 ):扩展了 Vector ,并实现了后进先出(LIFO, Last In First Out)的数据结构,也是一个同步(线程安全)的集合。它主要用于栈操作。与 Vector 有同样的性能问题。官方文档推荐使用 Deque 接口(双端队列)的实现类,如 ArrayDequeLinkedList 代替。

Set接口实现类介绍

Set 集合不允许包含重复的元素(判断两个元素是否相同:根据元素的 equals() 方法判断);Set 不能像 List 一样可以通过整数索引来访问元素; Set 不保证元素的顺序,除非使用了特定类型的 Set 实现。

Set接口常用方法:

Set 接口本身提供的方法不多,但因为它继承自 Collection ,所以它可以使用 Collection接口中定义的所有方法,例如:

  • add(E e):如果Set中尚未包含指定的元素,则将其添加到此集合中。
  • remove(Object o):从此集合中移除指定元素(如果存在)。
  • contains(Object o):如果此集合包含指定的元素,则返回true
  • size():返回此集合中的元素数量。
  • clear():移除此集合中的所有元素。
  • iterator():返回在此集合中的元素上进行迭代的迭代器。

Set接口的常见实现类:

  • HashSet
    • 最常用的 Set 实现之一。
    • 不保证元素的顺序,且允许 null 值。
    • 通过哈希表 实现,提供了 O(1) 时间性能的基本操作(如添加、删除和查询)。
  • LinkedHashSet
    • 继承自 HashSet ,但是通过维护一个双向链表来记住元素插入的顺序。
    • 提供了与 HashSet 相同的操作效率,并额外支持按插入顺序遍历集合。
  • TreeSet
    • 基于红黑树的数据结构,能够对元素进行排序。
    • 元素必须实现 Comparable 接口,或者在创建 TreeSet 时提供一个 Comparator ,以决定元素的排序方式。
    • 支持自然排序或定制排序。
  • EnumSet
    • 特别为枚举类型设计的高效实现:通过一个位向量( bit vector )来高效地存储和操作枚举类型的元素。
    • 必须由同一个枚举类型的所有元素组成。
    • 提供了非常快速的操作性能。

Queue接口实现类介绍

Queue 是专门用于表示队列的数据结构,队列通常遵循**先进先出( FIFO, First-In-First-Out )**原则,即最早加入队列的元素将首先被移除。不过,也有例外情况,比如优先级队列,它根据元素的优先级来决定服务顺序。

此外,Java还提供了 Deque (双端队列)接口,允许从两端进行插入和删除操作,适用于栈、队列以及其他需要双向访问的数据结构。

Queue接口常用方法:

  • add(E e) / offer(E e):向队列尾部添加一个元素。 add() 方法在插入失败时抛出异常,而 offer() 返回一个布尔值。
  • remove() / poll():从队列头部移除并返回一个元素。remove() 在队列为空时抛出异常,而poll()则返回null
  • element() / peek():获取但不移除队列头部的元素。 element() 方法在队列为空时抛出异常,而 peek() 返回 null

Queue接口的常见实现类:

  • LinkedList:实现了 Queue 接口,并且可以作为双端队列使用。它允许在两端进行高效的插入和删除操作。
  • PriorityQueue:基于 的数据结构,按照元素的自然顺序或通过提供的 Comparator 来进行排序。因此,它并不严格遵守FIFO原则,而是根据优先级来确定哪个元素最先出队。

Map接口

Map 接口是集合框架的一部分,但它并不继承自 Collection 接口。 Map 用于存储键值对( key-value pairs ),其中每个键都是唯一的,而值可以重复。通过键可以在 Map 中高效地查找、更新或删除对应的值。

Map接口和类关系:

Map接口常用方法:

  • 基本操作:
    • put(K key, V value):将指定的键值对插入到 Map 中。
    • get(Object key):根据键返回对应的值。
    • remove(Object key):根据键移除键值对。
    • clear():移除 Map 中的所有映射关系。
    • isEmpty():检查 Map 是否为空。
    • size():返回 Map 中键值对的数量。
  • 查询操作:
    • containsKey(Object key):判断 Map 是否包含指定的键。
    • containsValue(Object value):判断 Map 是否包含指定的值。
    • keySet():返回 Map 中所有键的集合视图。
    • values():返回 Map 中所有值的集合视图。
    • entrySet():返回 Map 中所有键值对的集合视图。

Map接口的常见实现类:

  • HashMap
    • 最常用的实现之一,基于哈希表实现。
    • 允许 null 键和 null 值。
    • 不保证顺序。
  • LinkedHashMap
    • 继承自 HashMap ,但通过维护双向链表来记住元素的插入顺序。
    • 可以基于访问顺序进行排序(适合实现LRU缓存)。
  • TreeMap
    • 基于红黑树 数据结构,按键的自然顺序或自定义的 Comparator 进行排序。
    • 不允许 null 键。
  • Hashtable(旧类,不推荐使用)
    • 类似于 HashMap ,但是是同步的(线程安全),性能较差。
    • 不允许 null 键和 null 值。
    • 替代类:ConcurrentHashMap,专门设计用于高并发环境的线程安全HashMap实现,通过分段锁(在 Java 8 前)或数组 + 链表/红黑树(在 Java 8 及以后使用 synchronized 和 CAS )实现高效的并发访问,允许多个线程同时读写而不会导致数据竞争,从而提供高并发场景下的线程安全和性能优化。
  • EnumMap
    • 专门用于键为枚举类型的情况(要求所有键必须来自同一个枚举类型),针对枚举类型的键进行了特别优化,提供了更高效的存储和访问速度。
相关推荐
Dontla11 分钟前
Dockerfile解析器指令(Parser Directive)指定语法版本,如:# syntax=docker/dockerfile:1
java·docker·eureka
彭于晏Yan13 分钟前
SpringBoot优化树形结构数据查询
java·spring boot·后端
AAA修煤气灶刘哥29 分钟前
缓存这「加速神器」从入门到填坑,看完再也不被产品怼慢
java·redis·spring cloud
练习时长一年35 分钟前
Spring事件监听机制(三)
java·后端·spring
月阳羊36 分钟前
【硬件-笔试面试题-69】硬件/电子工程师,笔试面试题(知识点:电机驱动电路的反馈电路)
java·经验分享·嵌入式硬件·面试
2301_781392521 小时前
用spring框架实现简单的MVC业务
java·后端·spring
phltxy1 小时前
SpringMVC 程序开发
java·后端·spring
至此流年莫相忘1 小时前
设计模式:模板方法模式
java·开发语言·设计模式
人机1011 小时前
Spring Security - FilterChainProxy
java
SimonKing1 小时前
Apache Commons Math3 使用指南:强大的Java数学库
java·后端·程序员