Java 中的集合 - 您必须知道的一切
Java 集合框架是 Java 编程语言的核心部分之一。几乎每种编程语言都使用集合。大多数编程语言都支持各种类型的集合,例如List、Set、Queue、Stack等。
什么是 Java 集合框架?
集合就像容器,将多个项目组合成一个单元。例如,一罐巧克力、一份姓名列表等。
每种编程语言中都会用到集合,而 Java 的出现也带来了一些集合类 – Vector、Stack、Hashtable、Array。
Java 1.2 提供了Collections Framework,它是用标准方式表示和操作 Java 中的 Collections 的架构。Java Collections Framework 由以下部分组成:
1. 接口
Java 集合框架接口提供了抽象数据类型来表示集合。
java.util.Collection是 Collections Framework 的根接口。它位于 Collections 框架层次结构的顶部。它包含每个 Collection 类都必须实现的一些重要方法,例如 size()、iterator()、add()、remove()、clear()。
其他一些重要接口包括 java.util.List、java.util.Set、java.util.Queue 和 java.util.Map。Map 是唯一不从 Collection 接口继承的接口,但它是 Collections 框架的一部分。所有集合框架接口都存在于 java.util 包中。
2.实现类
Java Collections框架提供了核心集合接口的实现类,我们可以使用它们在Java程序中创建不同类型的集合。
一些重要的集合类是 ArrayList、LinkedList、HashMap、TreeMap、HashSet 和 TreeSet。这些类解决了我们的大多数编程需求,但如果我们需要一些特殊的集合类,我们可以扩展它们来创建我们的自定义集合类。
Java 1.5 推出了线程安全集合类,允许我们在迭代集合时对其进行修改。其中一些是 CopyOnWriteArrayList、ConcurrentHashMap、CopyOnWriteArraySet。这些类位于 java.util.concurrent 包中。
所有集合类都存在于 java.util 和 java.util.concurrent 包中。
3.算法
算法是提供一些常见功能(例如搜索、排序和混洗)的有用方法。
集合框架类图
下面的类图显示了 Collections Framework 层次结构。为简单起见,我仅包括了常用的接口和类。
Java 集合框架的优点
Java Collections框架具有以下优点:
- 减少开发工作量– 它包含几乎所有常见类型的集合以及用于迭代和操作数据的有用方法。因此我们可以将更多精力集中在业务逻辑上,而不是设计集合 API。
- 更好的质量——使用经过充分测试的核心集合类比使用任何自己开发的数据结构可以提高我们的程序质量。
- 可重用性和互操作性
- 由于每个人都知道 Collection API 类,因此减少维护工作量。
Java 集合 API 接口
Java 集合接口是 Java 集合框架的基础。请注意,所有核心集合接口都是通用的;例如公共接口 Collection<E>。<E> 语法用于泛型,当我们声明 Collection 时,我们应该使用它来指定它可以包含的对象类型。通过在编译时对对象进行类型检查,它有助于减少运行时错误。
为了使核心集合接口的数量易于管理,Java 平台不为每种集合类型的每个变体提供单独的接口。如果调用了不支持的操作,集合实现将抛出 UnsupportedOperationException。
1. 收藏接口
这是集合层次结构的根。集合表示一组称为其元素的对象。Java 平台不提供此接口的任何直接实现。
该接口具有多种方法,可以告诉您集合中有多少个元素(size、isEmpty)、检查给定对象是否在集合中(contains)、从集合中添加和删除元素(add、remove)以及提供集合上的迭代器(iterator)。
Collection 接口还提供对整个集合起作用的批量操作方法 - containsAll、addAll、removeAll、retainAll、clear。
toArray 方法作为集合和需要输入数组的旧 API 之间的桥梁。
2. 迭代器接口
Iterator 接口提供了迭代 Collection 元素的方法。我们可以使用iterator()
方法获取迭代器的实例。Iterator 在 Java 集合框架中取代了Enumeration
。迭代器允许调用者在迭代过程中从底层集合中删除元素。集合类中的迭代器实现了迭代器设计模式。
3. 设置接口
Set 是不能包含重复元素的集合。此接口模拟了数学集合抽象,用于表示集合,例如一副牌。
Java 平台包含三种通用 Set 实现:HashSet
、TreeSet
和LinkedHashSet
。Set 接口不允许随机访问 Collection 中的元素。您可以使用迭代器或 foreach 循环来遍历 Set 中的元素。
4.列表界面
List是一个有序集合,可以包含重复元素。您可以从其索引访问任何元素。List 更像是具有动态长度的数组。List 是最常用的 Collection 类型之一。ArrayList
并且LinkedList
是 List 接口的实现类。
List 接口提供了有用的方法,可以在特定索引处添加元素、根据索引删除/替换元素以及使用索引获取子列表。
List strList = new ArrayList<>();
//add at last
strList.add(0, "0");
//add at specified index
strList.add(1, "1");
//replace
strList.set(1, "2");
//remove
strList.remove("1");
Collections 类为 List 提供了一些有用的算法 - 排序、随机播放、反向、二分搜索等。
5.队列接口
队列是用于在处理之前保存多个元素的集合。除了基本的集合操作外,队列还提供额外的插入、提取和检查操作。
队列通常(但不一定)以 FIFO(先进先出)方式对元素进行排序。例外情况是优先级队列,它根据提供的比较器或元素的自然顺序对元素进行排序。无论使用哪种顺序,队列的头部都是通过调用 remove 或 poll 删除的元素。在 FIFO 队列中,所有新元素都插入到队列的尾部。
6. Dequeue 接口
支持在两端插入和移除元素的线性集合。deque 的名称是“双端队列”的缩写,通常发音为“deck”。大多数 Deque 实现对它们可以包含的元素数量没有固定限制,但此接口支持容量受限的 Deque 以及没有固定大小限制的 Deque。
此接口定义了访问双端队列两端元素的方法。提供了插入、移除和检查元素的方法。
7. 地图界面
Java Map是将键映射到值的对象。映射不能包含重复的键:每个键最多可以映射到一个值。
Java平台包含三种通用的Map实现:HashMap、TreeMap和LinkedHashMap。
Map的基本操作有put、get、containsKey、containsValue、size、isEmpty。
8. ListIterator 接口
列表迭代器允许程序员沿任一方向遍历列表、在迭代期间修改列表以及获取迭代器在列表中的当前位置。
Java ListIterator没有当前元素;它的光标位置始终位于调用 previous() 返回的元素与调用 next() 返回的元素之间。
9. SortedSet 接口
SortedSet 是保持其元素按升序排列的 Set。提供了几个额外的操作来利用排序。Sorted Set 用于自然排序的集合,例如单词列表和成员名单。
10. SortedMap 接口
按升序键顺序维护其映射的映射。这是 SortedSet 的 Map 类似物。排序映射用于自然排序的键/值对集合,例如字典和电话簿。
Java 集合类
Java Collections 框架附带了许多接口的实现类。最常见的实现是ArrayList、HashMap和 HashSet 。 Java 1.5 包括 Concurrent 实现;例如 ConcurrentHashMap 和 CopyOnWriteArrayList 。通常 Collection 类不是线程安全的,并且它们的迭代器是快速失败的。在本节中,我们将了解常用的集合类。
1. HashSet 类
Java HashSet是 Set 接口的基本实现,由HashMap提供支持。它不保证集合的迭代顺序,并且允许空元素。
此类为基本操作(add
、remove
和)提供了恒定时间性能,前提是哈希函数将元素正确分散到存储桶中。我们可以为此集合设置初始容量和负载因子。负载因子衡量哈希映射在其容量自动增加之前contains
允许size
达到的满度。
2. TreeSet 类
NavigableSet
基于 的实现。TreeMap
元素使用其自然顺序进行排序,或者Comparator
根据使用哪个构造函数,按照创建集合时提供的顺序进行排序。
此实现为基本操作(添加、删除和包含)提供了保证的 log(n) 时间成本。
请注意,如果要正确实现 Set 接口,则由 set 维护的顺序(无论是否提供显式比较器)必须与 equals 一致。(有关与 equals 一致的精确定义,请参阅 Comparable 或 Comparator。)这是因为 Set 接口是根据 equals 操作定义的,但 TreeSet 实例使用其 compareTo(或 compare)方法执行所有元素比较,因此从 set 的角度来看,此方法视为相等的两个元素是相等的。
3.ArrayList 类
Java ArrayList是 List 接口的可调整大小数组实现。实现所有可选的列表操作,并允许所有元素(包括 null)。除了实现 List 接口之外,此类还提供方法来操作用于内部存储列表的数组的大小。(此类大致相当于 Vector,只是它是非同步的。)
size、isEmpty、get、set、iterator 和 list iterator 操作在常量时间内运行。add 操作在摊销常量时间内运行,也就是说,添加 n 个元素需要 O(n) 时间。所有其他操作都在线性时间内运行(粗略地说)。与 LinkedList 实现相比,常量因子较低。
进一步阅读:Java ArrayList 和 Iterator
4. LinkedList 类
List 和 Deque 接口的双向链表实现。实现所有可选的列表操作,并允许所有元素(包括 null)。
所有操作均按双向链表的预期方式执行。索引到列表中的操作将从开头或结尾(以更接近指定索引为准)遍历列表。
5. HashMap 类
基于哈希表的 Map 接口实现。此实现提供所有可选的映射操作,并允许使用空值和空键。HashMap 类大致相当于 Hashtable,只是它不同步并且允许使用空值。此类不保证映射的顺序。
get
此实现为基本操作(和)提供了恒定时间性能put
。它提供了构造函数来设置集合的初始容量和加载因子。
进一步阅读:HashMap 与 ConcurrentHashMap
6. TreeMap 类
基于红黑树的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据使用哪个构造函数,根据在创建映射时提供的 Comparator 进行排序。
此实现为 containsKey、get、put 和 remove 操作提供了有保证的 log(n) 时间成本。算法改编自 Cormen、Leiserson 和 Rivest 的《算法简介》中的算法。
请注意,如果要正确实现 Map 接口,TreeMap 所维护的顺序(与任何有序映射一样)以及是否提供显式比较器都必须与 equals 一致。(有关与 equals 一致的精确定义,请参阅 Comparable 或 Comparator。)这是因为 Map 接口是根据 equals 操作定义的,但有序映射使用其 compareTo(或 compare)方法执行所有键比较,因此从有序映射的角度来看,此方法视为相等的两个键是相等的。即使有序映射的顺序与 equals 不一致,其行为也是明确定义的;它只是未能遵守 Map 接口的一般约定。
7. PriorityQueue 类
队列按 FIFO 顺序处理其元素,但有时我们希望根据元素的优先级对其进行处理。在这种情况下,我们可以使用 PriorityQueue,并且在实例化 PriorityQueue 时我们需要提供 Comparator 实现。PriorityQueue 不允许空值,并且它是无界的。有关此内容的更多详细信息,请前往Java 优先级队列,您可以使用示例程序检查其用法。
Collections 类
Java Collections 类仅由操作或返回集合的静态方法组成。它包含操作集合的多态算法、“包装器”(返回由指定集合支持的新集合)以及一些其他零碎内容。
此类包含集合框架算法的方法,例如二分查找、排序、混洗、反转等。
同步包装器
同步包装器为任意集合添加了自动同步(线程安全)。六个核心集合接口(Collection、Set、List、Map、SortedSet 和 SortedMap)均有一个静态工厂方法。
public static Collection synchronizedCollection(Collection c);
public static Set synchronizedSet(Set s);
public static List synchronizedList(List list);
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);
public static SortedSet synchronizedSortedSet(SortedSet s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);
这些方法中的每一个都返回由指定集合备份的同步(线程安全)集合。
不可修改的包装器
不可修改的包装器通过拦截所有修改集合的操作并抛出一个 来剥夺修改集合的能力UnsupportedOperationException
。它的主要用途是;
- 使集合在构建后不可变。在这种情况下,最好不要维护对后备集合的引用。这绝对保证了不变性。
- 允许某些客户端以只读方式访问您的数据结构。您保留对后备集合的引用,但分发对包装器的引用。这样,客户端可以查看但不能修改,而您保持完全访问权限。
public static Collection unmodifiableCollection(Collection<? extends T> c);
public static Set unmodifiableSet(Set<? extends T> s);
public static List unmodifiableList(List<? extends T> list);
public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m);
public static SortedSet unmodifiableSortedSet(SortedSet<? extends T> s);
public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m);
线程安全集合类
Java 1.5 Concurrent 包 ( java.util.concurrent
) 包含线程安全集合类,允许在迭代时修改集合。根据设计,迭代器是快速失败的,并会抛出 ConcurrentModificationException。其中一些类是CopyOnWriteArrayList
、、ConcurrentHashMap
。CopyOnWriteArraySet
集合 API 算法
Java 集合框架提供了常用的算法实现,例如排序和搜索。Collections 类包含这些方法实现。这些算法中的大多数适用于 List,但其中一些适用于所有类型的集合。
1. 排序
排序算法对 List 进行重新排序,使其元素按照排序关系升序排列。提供了两种形式的操作。简单形式采用 List,并根据其元素的自然顺序对其进行排序。排序的第二种形式除了 List 外还采用 Comparator,并使用 Comparator 对元素进行排序。
2. 改组
洗牌算法会破坏列表中可能存在的任何顺序痕迹。也就是说,该算法根据来自随机源的输入对列表进行重新排序,使得所有可能的排列都以相同的概率发生(假设随机源是公平的)。该算法在实现机会游戏时很有用。
3. 搜索
binarySearch 算法在排序列表中搜索指定元素。该算法有两种形式。第一种采用 List 和要搜索的元素(“搜索键”)。
此形式假定列表按照其元素的自然顺序按升序排列。
第二种形式除了列表和搜索键之外,还采用比较器,并假定列表根据指定的比较器按升序排列。
在调用二分搜索之前,可以使用排序算法对列表进行排序。
4. 构图
频率和不相交算法测试一个或多个集合组成的某些方面。
- 频率:统计指定元素在指定集合中出现的次数
- disjoint:确定两个 Collection 是否不相交;即它们是否不包含共同的元素
5. 最小值和最大值
min 和 max 算法分别返回指定 Collection 中包含的最小和最大元素。这两个操作都有两种形式。简单形式仅接受 Collection,并根据元素的自然顺序返回最小(或最大)元素。
Java 8 集合 API 功能
Java 8 最大的变化与 Collection API 有关。一些重要的变化和改进包括:
- 介绍用于顺序和并行处理的 Stream API,您应该阅读Java Stream API 教程了解更多详细信息。
- Iterable 接口已扩展,并具有用于对集合进行迭代的默认方法 forEach()。
- Lambda 表达式和 Functional 接口对 Collection API 类最有益。
Java 10 集合 API 变更
- List.copyOf、Set.copyOf 和 Map.copyOf 方法创建不可修改的集合。
- Collectors 类获取各种用于收集不可修改集合(Set、List、Map)的方法。这些方法名称为 toUnmodifiableList、toUnmodifiableSet 和 toUnmodifiableMap。
让我们看一个关于这些新的Java 10 Collections API 方法的使用示例。
package com.journaldev.collections;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class JDK10CollectionFunctions {
public static void main(String[] args) {
// 1. List, Set, Map copyOf(Collection) method
List<String> actors = new ArrayList<>();
actors.add("Jack Nicholson");
actors.add("Marlon Brando");
System.out.println(actors);
// prints [Jack Nicholson, Marlon Brando]
// New API added - Creates an UnModifiable List from a List.
List<String> copyOfActors = List.copyOf(actors);
System.out.println(copyOfActors);
// prints [Jack Nicholson, Marlon Brando]
// copyOfActors.add("Robert De Niro"); Will generate
// UnsupportedOperationException
actors.add("Robert De Niro");
System.out.println(actors);
// prints [Jack Nicholson, Marlon Brando, Robert De Niro]
System.out.println(copyOfActors);
// prints [Jack Nicholson, Marlon Brando]
// 2. Collectors class toUnmodifiableList, toUnmodifiableSet, and
// toUnmodifiableMap methods
List<String> collect = actors.stream().collect(Collectors.toUnmodifiableList());
System.out.println(collect);
}
}
Java 11 集合 API 变更
Collection 接口中添加了新的默认方法toArray(IntFunction<T[]> generator)
。此方法返回一个包含此集合中所有元素的数组,并使用提供的生成器函数分配返回的数组。
package com.journaldev.collections;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JDK11CollectionFunctions {
public static void main(String[] args) {
/*
* JDK 11 New Method in Collection interface
* default <T> T[] toArray(IntFunction<T[]> generator) {
* return toArray(generator.apply(0)); }
*/
List<String> strList = new ArrayList<>();
strList.add("Java");
strList.add("Python");
strList.add("Android");
String[] strArray = strList.toArray(size -> new String[size]);
System.out.println(Arrays.toString(strArray));
strArray = strList.toArray(size -> new String[size + 5]);
System.out.println(Arrays.toString(strArray));
strArray = strList.toArray(size -> new String[size * 3]);
System.out.println(Arrays.toString(strArray));
}
}
输出:
[Java, Python, Android]
[Java, Python, Android, null, null]
[Java, Python, Android]
集合类简介
下表提供了常用集合类的基本细节。
下载地址:Java 集合类
收藏 | 订购 | 随机存取 | 键值 | 重复元素 | 空元素 | 线程安全 |
---|---|---|---|---|---|---|
数组列表 | ||||||
链表 | ||||||
哈希集 | ||||||
树集 | ||||||
哈希表 | ||||||
树形图 | ||||||
向量 | ||||||
哈希表 | ||||||
特性 | ||||||
堆 | ||||||
写时复制数组列表 | ||||||
并发哈希映射 | ||||||
写时复制数组集 |
我希望本教程解释了 Java 集合框架中的大部分主题。请通过评论分享您的观点。
参考:Oracle 文档