什么是 Java 集合
尽管 Java 已经过了 25 岁生日,仍然是当今最受欢迎的编程语言之一。超过 100 万个网站通过某种形式在使用 Java,超过 三分之一 的软件开发人员的工具箱中有 Java。
Java 在它的整个生命历程中经历了重大的演变。一个早期的进步出现在 1998 年,当时 Java 引入了 Collections Framework(Java Collection Framework,JCF),简化了操作 Java 对象的任务。JCF 为集合提供了标准化的接口和通用方法,减少了编程工作,并提升了 Java 程序的运行速度。
理解 Java 集合和 Java Collections Framework 之间的区别是至关重要的。Java 集合只是表示一组 Java 对象的数据结构。开发人员可以像处理其他数据类型一样处理集合,执行搜索或操作集合内容等常见任务。
Set 接口(java.util.Set)就是 Java 集合的一个例子。Set 是一种集合,不允许出现重复元素,也不以任何特定的顺序存储元素。Set 接口继承了 Collection(java.util.Collection)的方法,并且只包含这些方法。
除了集合之外,还有队列(java.util.Queue)和 Map(java.util.Map)。Map 并不是真正意义上的集合,因为它们没有 继承集合接口 ,但开发人员可以像操作集合一样操作 Map。集合、队列、列表和 Map 都有后代,比如排序集合(java.util.SortedSet)和可导航 Map(java.util.NavigableMap)。
在使用集合时,开发人员需要熟悉和理解一些特定的集合相关术语。
-
可修改与不可修改——正如这些术语表面上所表明的,不同的集合可能支持也可能不支持修改操作。
-
可变集合与不可变集合——不可变集合在创建后不能被修改。虽然在某些情况下,不可修改的集合仍然可能由于其他代码的访问而发生变化,但不可变集合会阻止这种变更。不可变集合是指能够保证 Collection 对象中不会有任何变更的集合,而不可修改的集合是指不允许“add”或“clear”等修改操作的集合。
-
固定大小与可变大小——这些术语仅与集合的大小有关,与集合是可修改还是可变无关。
-
随机访问与顺序访问——如果一个集合允许为每一个元素建立索引,那么它就是可随机访问的。在顺序访问集合中,必须通过所有前面的元素到达指定的元素。顺序访问集合更容易扩展,但搜索时间更长。初学者可能会难以理解不可修改集合和不可变集合之间的区别。不可修改集合不一定是不可变的。实际上,不可修改集合通常是可修改集合的包装器,其他代码仍然可以访问和修改被包装的可修改集合。通常需要使用集合一些时间才能在一定程度上理解不可修改集合和不可变集合。
例如,我们将创建一个可修改的按市值排名前五的加密货币列表。你可以使用 java.util.Collections.unmodifiableList()方法创建底层可修改列表的不可修改版本。你仍然可以修改底层列表,它只是被包装成不可修改列表,但你不能直接修改不可修改的版本。
import java.util.*;
public class UnmodifiableCryptoListExample {
public static void main(String[] args) {
List<String> cryptoList = new ArrayList<>();
Collections.addAll(cryptoList, "BTC", "ETH", "USDT", "USDC", "BNB");
List<String> unmodifiableCryptoList = Collections.unmodifiableList(cryptoList);
System.out.println("Unmodifiable crypto List: " + unmodifiableCryptoList);
// 尝试在可修改列表中再添加一种加密货币,并显示在不可修改列表中
cryptoList.add("BUSD");
System.out.println("New unmodifiable crypto List with new element:" + unmodifiableCryptoList);
// 尝试添加并显示一个额外的加密货币到不可修改列表中——unmodifiableCryptoList.add将抛出一个未捕获的异常,println代码将无法被执行
unmodifiableCryptoList.add("XRP");
System.out.println("New unmodifiable crypto List with new element:" + unmodifiableCryptoList);
}
}
复制代码
在运行代码时,你将看到对底层可修改列表添加的内容显示为对不可修改列表的修改。
但这与你创建了一个不可变列表并试图修改底层列表不同。有许多种方法可以基于现有的 可修改列表创建不可变列表 ,下面我们使用 List.copyOf()方法创建了一个不可变列表。
import java.util.*;
public class UnmodifiableCryptoListExample {
public static void main(String[] args) {
List<String> cryptoList = new ArrayList<>();
Collections.addAll(cryptoList, "BTC", "ETH", "USDT", "USDC", "BNB");
List immutableCryptoList = List.copyOf(cryptoList);
System.out.println("Underlying crypto list:" + cryptoList)
System.out.println("Immutable crypto ist: " + immutableCryptoList);
// 尝试添加更多的加密货币到可修改列表,但不可变列表并没有显示变化
cryptoList.add("BUSD");
System.out.println("New underlying list:" + cryptoList);
System.out.println("New immutable crypto List:" + immutableCryptoList);
// 尝试添加并显示一个新的加密货币到不可修改的列表中
immutableCryptoList.add("XRP");
System.out.println("New unmodifiable crypto List with new element:" + immutableCryptoList);
}
}
复制代码
修改底层的列表后,不可变列表不显示变更。尝试修改不可变列表会直接导致抛出 UnsupportedOperationException。
集合与 Java Collections Framework 的关系
在引入 JCF 之前,开发人员可以使用几个特殊的类,即 Array、Vector 和 Hashtable。但这些类有很大的局限性,除了缺乏公共接口之外,它们还难以扩展。
JCF 提供了一个用于处理集合的通用架构。集合接口包含了几个不同的组件。
-
公共接口——主要集合类型的表示,包括集合、列表和 Map;
-
实现——集合接口的特定实现,从通用的到特殊的再到抽象的。此外,还有一些与旧的 Array、Vector 和 Hashtable 类相关的遗留实现;
-
算法——用于操作集合的静态方法;
-
基础结构——对各种集合接口的底层支持。与之前相比,JCF 为开发人员提供了许多好处。值得注意的是,JCF 降低了开发人员对自己编写数据结构的需求,从而提高了 Java 编程的效率。
但是,JCF 也从根本上改变了开发人员使用 A