JAVA集合框架是每个开发者都绕不开的话题,也是我们要熟练掌握的核心之一,它为我们提供了一整套强大的工具,用于存储、组织和操作数据。让我们一起来深入了解这个重要的主题。
📦 什么是集合框架?
Java 集合框架是一组接口、类和算法的集合,用于处理和管理数据。它提供了多种数据结构,包括 List、Set、Map 等,以满足不同场景下的需求。
🔢 不同类型的集合
-
List: 有序集合,允许重复元素。例如 ArrayList、LinkedList、Vector。
-
Set: 无序集合,不允许重复元素。例如 HashSet、LinkedHashSet、TreeSet。
-
Map: 键值对的集合。例如 HashMap、LinkedHashMap、TreeMap。
-
附上一张我自己整理的图
🔄 遍历集合
在Java中,你可以使用多种方式来遍历集合。以下是5种常用的遍历集合的方式:
使用增强for循环:
- 增强for循环(也称为for-each循环)是一种简单的遍历集合的方式。它适用于所有实现了
Iterable
接口的集合,包括数组、List、Set等。
List list = new ArrayList();
for (String item : list) {
System.out.println(item);
}
使用迭代器(Iterator):
- 迭代器是一种更通用的遍历方式,适用于所有实现了
Iterable
接口的集合。它允许你在遍历过程中删除元素。
List list = new ArrayList();
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
使用Java 8的Stream API:
- Java 8引入的Stream API提供了强大的集合处理功能,包括过滤、映射、归约等操作。你可以使用
forEach
方法来遍历元素。
List list = new ArrayList();
list.stream().forEach(item -> System.out.println(item));
使用Lambda表达式和方法引用:
- Java 8还引入了Lambda表达式和方法引用,可以简化遍历集合的代码。
List list = new ArrayList();
list.forEach(System.out::println); // 使用方法引用
使用传统的for循环:
- 你可以使用传统的for循环来遍历数组或List,通过索引访问元素。
List list = new ArrayList();
for (int i = 0; i < list.size(); i++) {
String item = list.get(i);
System.out.println(item);
}
不同的遍历方式适用于不同的情况和需求。通常来说,增强for循环和Stream API更加简洁和易读,而迭代器适用于需要在遍历过程中删除元素的情况,传统for循环则适用于数组和需要访问索引的情况。选择适合自己的才是最重要的。
🚧 线程安全性
线程非安全
- ArrayList:
ArrayList
不是线程安全的,多个线程同时修改一个ArrayList
实例可能导致不一致的状态。 - HashMap:
HashMap
也是非线程安全的。多线程环境下,如果多个线程同时修改一个HashMap
实例,可能会导致数据丢失或不一致的问题。
线程安全
- Vector:
Vector
是线程安全的List
实现,可以确保多个线程安全地访问和修改它。 - HashTable:
HashTable
是线程安全的Map
实现,类似于HashMap
,但它的方法都是同步的,因此可以在多线程环境下使用。 - Collections 类的静态方法来包装非线程安全的集合,使其变为线程安全。例如,
Collections.synchronizedList
和Collections.synchronizedMap
可以用来包装ArrayList
和HashMap
,生成一个线程安全的List
和Map
。 - ConcurrentHashMap:
ConcurrentHashMap
是 Java 5 引入的高度并发的线程安全的Map
实现,支持高度并发读写操作,性能比HashTable
好(看了源码就会了解:ConcurrentHashMap
采用的是分段锁
,而HashTable
底层使用的是通过synchronized
来保证线程安全的)。
⚖️ 性能考虑
ArrayList:
- 插入:在列表末尾进行插入操作的性能非常高,因为它的底层是数组。平均时间复杂度为 O(1)。
- 查询:随机访问元素的性能很好,因为可以通过索引进行快速访问,平均时间复杂度为 O(1)。但在列表的开头或中间插入或删除元素时,可能需要移动后续元素,导致较差的性能。
LinkedList:
- 插入:在列表的开头或中间进行插入操作的性能较好,因为它是基于链表实现的,插入元素只需要改变节点的引用。平均时间复杂度为 O(1)。
- 查询:随机访问元素的性能较差,因为需要遍历链表来查找元素,平均时间复杂度为 O(n)。但在列表的开头或中间插入或删除元素时,性能较好。
HashSet:
- 插入:插入元素的性能通常很好,因为它是基于哈希表实现的,插入元素的平均时间复杂度为 O(1)。
- 查询:查找元素的性能也很好,平均时间复杂度为 O(1)。但在哈希冲突发生时,性能可能会下降,因为需要在冲突的链表上进行线性查找。
TreeSet:
- 插入:插入元素的性能较好,平均时间复杂度为 O(log n),因为它是基于红黑树实现的。
- 查询:查找元素的性能也较好,平均时间复杂度为 O(log n)。
HashMap:
- 插入:插入键值对的性能通常很好,平均时间复杂度为 O(1)。但在哈希冲突发生时,性能可能会下降。
- 查询:查找键对应的值的性能也很好,平均时间复杂度为 O(1)。但在哈希冲突发生时,性能可能会下降,需要线性查找。
TreeMap:
- 插入:插入键值对的性能较好,平均时间复杂度为 O(log n),因为它是基于红黑树实现的。
- 查询:查找键对应的值的性能也较好,平均时间复杂度为 O(log n)。
ConcurrentHashMap:
- 插入和查询:
ConcurrentHashMap
在高并发环境中表现良好,多个线程可以同时插入和查询,性能较好。它通过分段锁来实现并发性。
tips:具体使用哪种需要结合业务的实际情况考虑,如果需要高性能插入和查询操作,不用保持元素顺序的情况下使用HashSet
和 HashMap
,如果需要有序的集合,则可以使用TreeSet
和 TreeMap
,如果是在多线程情况下则使用ConcurrentHashMap
较为合适。
此篇我们主要介绍了集合框架有哪些
、遍历方式
、线程安全
和性能
多方面介绍了集合框架的基础信息,由于篇幅有限,我们下章会着重介绍相关集合的相关面试题,有需要的小伙伴可以点赞关注哦。