Java Collection 包使用指南
1. Collection 框架概览
Java Collection 框架是一组用于存储和操作对象的接口和类,位于 java.util
包中。主要包括以下几个部分:
- 接口层:定义各种集合的抽象数据类型
- 实现层:提供各种接口的具体实现
- 算法层:提供对集合进行操作的各种静态方法
2. 主要接口体系
scss
Collection (根接口)
├─ List (有序、可重复)
│ ├─ ArrayList
│ ├─ LinkedList
│ └─ Vector
│ └─ Stack
├─ Set (无序、不可重复)
│ ├─ HashSet
│ ├─ LinkedHashSet
│ └─ TreeSet
└─ Queue (队列)
├─ LinkedList
├─ PriorityQueue
└─ Deque
├─ LinkedList
└─ ArrayDeque
Map (映射接口)
├─ HashMap
├─ LinkedHashMap
├─ TreeMap
├─ Hashtable
└─ ConcurrentHashMap
3. List 接口及实现
3.1 ArrayList
java
// 创建ArrayList
List<String> list = new ArrayList<>();
// 添加元素
list.add("Java");
list.add("Python");
list.add(0, "C++"); // 在指定位置添加
// 访问元素
String first = list.get(0);
// 修改元素
list.set(1, "JavaScript");
// 移除元素
list.remove(0);
list.remove("Python");
// 遍历
for (String item : list) {
System.out.println(item);
}
// 使用Lambda表达式遍历
list.forEach(System.out::println);
3.2 LinkedList
java
// 创建LinkedList
LinkedList<String> linkedList = new LinkedList<>();
// 特有方法(队列操作)
linkedList.addFirst("First");
linkedList.addLast("Last");
String first = linkedList.getFirst();
String last = linkedList.getLast();
String polled = linkedList.poll(); // 移除并返回第一个元素
linkedList.offer("New Element"); // 添加到末尾
// 双向链表操作
linkedList.add("Middle");
linkedList.removeFirst();
linkedList.removeLast();
4. Set 接口及实现
4.1 HashSet
java
// 创建HashSet
Set<String> set = new HashSet<>();
// 添加元素(自动去重)
set.add("Java");
set.add("Python");
set.add("Java"); // 重复元素,不会被添加
// 检查元素是否存在
boolean contains = set.contains("Java");
// 移除元素
set.remove("Python");
// 遍历
for (String item : set) {
System.out.println(item);
}
// 转换为数组
String[] array = set.toArray(new String[0]);
4.2 TreeSet
java
// 创建TreeSet(默认自然排序)
Set<Integer> treeSet = new TreeSet<>();
// 添加元素
for (int i = 5; i > 0; i--) {
treeSet.add(i); // 会自动排序为[1,2,3,4,5]
}
// 范围查询
Set<Integer> subset = treeSet.subSet(2, 4); // [2,3]
Integer first = treeSet.first(); // 1
Integer last = treeSet.last(); // 5
// 自定义排序
Set<String> customSet = new TreeSet<>((s1, s2) -> s2.compareTo(s1)); // 降序排列
5. Map 接口及实现
5.1 HashMap
java
// 创建HashMap
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("Java", 100);
map.put("Python", 85);
map.put("JavaScript", 90);
// 获取值
int javaScore = map.get("Java");
Integer cppScore = map.getOrDefault("C++", 0); // 如果键不存在,返回默认值
// 检查键是否存在
boolean containsKey = map.containsKey("Java");
// 移除元素
map.remove("Python");
// 遍历方式1:遍历键
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
// 遍历方式2:遍历entrySet(更高效)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 遍历方式3:使用Lambda
map.forEach((key, value) -> System.out.println(key + ": " + value));
5.2 LinkedHashMap
java
// 创建LinkedHashMap(保持插入顺序)
Map<String, String> linkedMap = new LinkedHashMap<>();
linkedMap.put("A", "1");
linkedMap.put("B", "2");
linkedMap.put("C", "3");
// 遍历顺序为A, B, C
// 访问顺序(LRU实现)
Map<String, String> lruMap = new LinkedHashMap<>(16, 0.75f, true);
lruMap.put("A", "1");
lruMap.put("B", "2");
lruMap.get("A"); // 访问后,A会移到最后
// 遍历顺序变为B, A
5.3 TreeMap
java
// 创建TreeMap(按键排序)
Map<Integer, String> treeMap = new TreeMap<>();
treeMap.put(3, "Three");
treeMap.put(1, "One");
treeMap.put(2, "Two");
// 遍历顺序为1, 2, 3
// 获取子Map
SortedMap<Integer, String> subMap = treeMap.subMap(1, 3); // {1=One, 2=Two}
Integer firstKey = treeMap.firstKey(); // 1
Integer lastKey = treeMap.lastKey(); // 3
// 自定义排序
Map<String, Integer> customTreeMap = new TreeMap<>((s1, s2) -> s2.compareTo(s1));
6. Queue 和 Deque
6.1 PriorityQueue
java
// 创建优先队列(默认小顶堆)
PriorityQueue<Integer> pq = new PriorityQueue<>();
// 添加元素
pq.offer(5);
pq.offer(1);
pq.offer(3);
pq.offer(2);
// 取出元素(按优先级)
while (!pq.isEmpty()) {
System.out.println(pq.poll()); // 输出:1, 2, 3, 5
}
// 创建大顶堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
6.2 Deque(双端队列)
java
// 创建双端队列
Deque<String> deque = new ArrayDeque<>();
// 添加元素
deque.addFirst("First");
deque.addLast("Last");
deque.offerFirst("Very First");
deque.offerLast("Very Last");
// 获取元素
String first = deque.getFirst(); // 获取但不移除
String last = deque.getLast();
// 移除元素
String pollFirst = deque.pollFirst(); // 移除并返回第一个
String pollLast = deque.pollLast(); // 移除并返回最后一个
// 栈操作(LIFO)
deque.push("Top"); // 相当于addFirst
String popped = deque.pop(); // 相当于pollFirst
7. 集合工具类 Collections
java
// 创建不可变集合
List<String> immutableList = Collections.unmodifiableList(new ArrayList<>());
Set<String> immutableSet = Collections.unmodifiableSet(new HashSet<>());
Map<String, String> immutableMap = Collections.unmodifiableMap(new HashMap<>());
// JDK 9+ 更简洁的方式
List<String> ofList = List.of("A", "B", "C");
Set<String> ofSet = Set.of("A", "B", "C");
Map<String, String> ofMap = Map.of("A", "1", "B", "2");
// 同步集合(线程安全)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
// 排序
List<Integer> numbers = new ArrayList<>(List.of(5, 3, 1, 4, 2));
Collections.sort(numbers); // 升序
Collections.sort(numbers, Collections.reverseOrder()); // 降序
// 查找
int index = Collections.binarySearch(numbers, 3); // 二分查找,要求集合已排序
// 填充
Collections.fill(numbers, 0); // 所有元素设为0
// 复制
Collections.copy(new ArrayList<>(numbers.size()), numbers);
// 最大值和最小值
Integer max = Collections.max(numbers);
Integer min = Collections.min(numbers);
8. 集合流操作(Java 8+)
java
List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry", "Date", "Apple");
// 过滤
List<String> filtered = fruits.stream()
.filter(f -> f.length() > 5)
.collect(Collectors.toList());
// 映射
List<Integer> lengths = fruits.stream()
.map(String::length)
.collect(Collectors.toList());
// 去重
List<String> distinct = fruits.stream()
.distinct()
.collect(Collectors.toList());
// 排序
List<String> sorted = fruits.stream()
.sorted()
.collect(Collectors.toList());
// 聚合
long count = fruits.stream().count();
Optional<String> first = fruits.stream().findFirst();
Optional<String> any = fruits.stream().findAny();
boolean allMatch = fruits.stream().allMatch(f -> f.length() > 3);
// 收集到不同集合
Set<String> fruitSet = fruits.stream()
.collect(Collectors.toSet());
Map<String, Integer> fruitLengthMap = fruits.stream()
.distinct()
.collect(Collectors.toMap(f -> f, String::length));
// 分组
Map<Integer, List<String>> groupByLength = fruits.stream()
.collect(Collectors.groupingBy(String::length));
9. 集合性能比较
集合类型 | 实现 | 随机访问 | 添加/删除首元素 | 添加/删除尾元素 | 添加/删除中间元素 | 查找元素 |
---|---|---|---|---|---|---|
ArrayList | 动态数组 | O(1) | O(n) | O(1) | O(n) | O(n) |
LinkedList | 双向链表 | O(n) | O(1) | O(1) | O(1) | O(n) |
HashSet | 哈希表 | 不支持 | O(1) | O(1) | O(1) | O(1) |
TreeSet | 红黑树 | 不支持 | O(log n) | O(log n) | O(log n) | O(log n) |
HashMap | 哈希表+链表/红黑树 | 不支持 | O(1) | O(1) | O(1) | O(1) |
TreeMap | 红黑树 | 不支持 | O(log n) | O(log n) | O(log n) | O(log n) |
ArrayDeque | 循环数组 | 不支持 | O(1) | O(1) | 不适用 | O(n) |
10. 最佳实践
10.1 选择合适的集合
- 需要快速随机访问:使用ArrayList
- 需要频繁插入删除中间元素:使用LinkedList
- 需要无序且不重复:使用HashSet
- 需要有序且不重复:使用TreeSet或LinkedHashSet
- 需要键值映射且无序:使用HashMap
- 需要键值映射且有序:使用TreeMap或LinkedHashMap
- 需要FIFO队列:使用LinkedList或ArrayDeque
- 需要优先队列:使用PriorityQueue
10.2 性能优化技巧
- 初始化时指定集合大小,减少扩容开销
java
List<String> list = new ArrayList<>(100); // 预估大小
Map<String, Object> map = new HashMap<>(16, 0.75f); // 初始容量和负载因子
- 遍历Map时使用entrySet而非keySet+get
java
// 推荐
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
}
// 不推荐
for (String key : map.keySet()) {
Integer value = map.get(key); // 额外的查找操作
}
- 优先使用集合工厂方法(Java 9+)
java
// 更简洁、更高效
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
- 使用并行流处理大数据集(但需注意线程安全)
java
List<String> result = largeList.parallelStream()
.filter(s -> s.length() > 5)
.collect(Collectors.toList());
10.3 线程安全
- 单线程环境:使用普通集合
- 多线程环境:
- 读多写少:使用
CopyOnWriteArrayList
、CopyOnWriteArraySet
- 高并发:使用
ConcurrentHashMap
- 一般情况:使用
Collections.synchronizedXxx()
包装器
- 读多写少:使用
10.4 避免常见陷阱
- ConcurrentModificationException:不要在遍历集合时直接修改集合(使用迭代器的remove方法或拷贝集合后操作)
- Autoboxing/Unboxing开销:大数据量操作时考虑使用原始类型集合(如Trove库)
- 内存泄漏:使用集合时注意及时移除不再使用的元素
- 过度同步:避免不必要的同步导致性能下降
11. 新特性(Java 8+)
11.1 集合工厂方法(Java 9)
java
// 创建不可变集合
List.of(1, 2, 3);
Set.of("a", "b", "c");
Map.of("key1", 1, "key2", 2);
Map.ofEntries(
Map.entry("key1", 1),
Map.entry("key2", 2)
);
11.2 集合增强(Java 10)
java
// 局部变量类型推断
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();
11.3 记录类与集合(Java 16+)
java
// 记录类作为集合元素更简洁
record Person(String name, int age) {}
List<Person> people = List.of(
new Person("Alice", 30),
new Person("Bob", 25)
);
掌握Java Collection框架的使用对于高效开发Java应用至关重要。选择合适的集合类型,遵循最佳实践,可以显著提升代码质量和性能。希望这份指南对你有所帮助!