一、集合框架概述
1. 集合框架体系结构
Java集合框架(Java Collections Framework, JCF)位于java.util
包中,包含三大核心接口:
- Collection:单列数据集合的根接口
- List:有序可重复集合
- Set:无序不可重复集合
- Queue:队列集合
- Map:双列键值对集合
- Iterator:集合遍历接口
2. 核心接口继承关系
Collection
├── List
│ ├── ArrayList
│ ├── LinkedList
│ └── Vector
│ └── Stack
├── Set
│ ├── HashSet
│ │ └── LinkedHashSet
│ └── SortedSet
│ └── TreeSet
└── Queue├── Deque│ ├── ArrayDeque│ └── LinkedList└── PriorityQueueMap
├── HashMap
│ └── LinkedHashMap
├── Hashtable
└── SortedMap└── TreeMap
二、基础集合使用
1. List接口实现
ArrayList
// 创建ArrayList
List<String> arrayList = new ArrayList<>();// 添加元素
arrayList.add("Java");
arrayList.add("Python");
arrayList.add(1, "C++"); // 在指定位置插入// 访问元素
String lang = arrayList.get(0); // "Java"// 遍历
for (String s : arrayList) {System.out.println(s);
}// 删除元素
arrayList.remove("Python");
arrayList.remove(0);
LinkedList
// 创建LinkedList
List<String> linkedList = new LinkedList<>();// 特有方法
LinkedList<String> list = (LinkedList<String>) linkedList;
list.addFirst("First");
list.addLast("Last");
String first = list.getFirst();
String last = list.getLast();
2. Set接口实现
HashSet
Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Banana");
hashSet.add("Apple"); // 重复元素不会被添加System.out.println(hashSet); // [Apple, Banana]
TreeSet
Set<Integer> treeSet = new TreeSet<>((a, b) -> b - a); // 自定义排序
treeSet.add(5);
treeSet.add(2);
treeSet.add(8);System.out.println(treeSet); // [8, 5, 2]
3. Map接口实现
HashMap
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Alice", 25);
hashMap.put("Bob", 30);
hashMap.put("Charlie", 28);// 获取值
int age = hashMap.get("Bob");// 遍历
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
}
TreeMap
Map<String, Integer> treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
treeMap.put("Banana", 3);
treeMap.put("apple", 5);
treeMap.put("Orange", 2);System.out.println(treeMap); // {apple=5, Banana=3, Orange=2}
三、集合转换操作
1. 集合间相互转换
List ↔ Set
// List转Set(去重)
List<String> listWithDuplicates = Arrays.asList("A", "B", "A", "C");
Set<String> set = new HashSet<>(listWithDuplicates); // [A, B, C]// Set转List
List<String> listFromSet = new ArrayList<>(set);
数组 ↔ List
// 数组转List
String[] array = {"Java", "Python", "C++"};
List<String> list = Arrays.asList(array); // 固定大小List
List<String> mutableList = new ArrayList<>(Arrays.asList(array));// List转数组
String[] newArray = list.toArray(new String[0]);
Map ↔ Set
// Map的key转Set
Set<String> keys = hashMap.keySet();// Map的entry转Set
Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();// Set转Map(需要元素包含键值信息)
Set<Pair<String, Integer>> pairSet = new HashSet<>();
// ...添加元素
Map<String, Integer> mapFromSet = pairSet.stream().collect(Collectors.toMap(Pair::getKey, Pair::getValue));
2. 不可变集合
Java 9+创建不可变集合
List<String> immutableList = List.of("A", "B", "C");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, Integer> immutableMap = Map.of("A", 1, "B", 2);// 尝试修改会抛出UnsupportedOperationException
// immutableList.add("D"); // 错误
Collections工具类创建
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> unmodifiableList = Collections.unmodifiableList(list);
四、集合流式处理(Java 8+)
1. 基本流操作
过滤与映射
List<String> languages = Arrays.asList("Java", "Python", "C++", "JavaScript", "Ruby");// 过滤长度大于3的元素
List<String> filtered = languages.stream().filter(s -> s.length() > 3).collect(Collectors.toList()); // [Java, Python, JavaScript, Ruby]// 转换为大写
List<String> upperCase = languages.stream().map(String::toUpperCase).collect(Collectors.toList());
聚合操作
// 统计
long count = languages.stream().count();
Optional<String> max = languages.stream().max(Comparator.naturalOrder());// 求和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum);
2. 高级流操作
分组与分区
// 按长度分组
Map<Integer, List<String>> groupByLength = languages.stream().collect(Collectors.groupingBy(String::length));
// {2=[C++], 4=[Java, Ruby], 6=[Python], 10=[JavaScript]}// 分区(满足条件的和其他的)
Map<Boolean, List<String>> partition = languages.stream().collect(Collectors.partitioningBy(s -> s.startsWith("J")));
// {false=[Python, C++, Ruby], true=[Java, JavaScript]}
并行流
// 顺序流
long count = languages.stream().filter(s -> s.length() > 3).count();// 并行流(大数据量性能更好)
long parallelCount = languages.parallelStream().filter(s -> s.length() > 3).count();
五、集合与数组转换
1. 集合转数组
传统方式
List<String> list = Arrays.asList("A", "B", "C");
String[] array = list.toArray(new String[0]); // 推荐使用空数组
Java 8+ Stream方式
String[] array = list.stream().toArray(String[]::new);
2. 数组转集合
标准方式
String[] array = {"A", "B", "C"};// 固定大小List(不可修改)
List<String> asList = Arrays.asList(array);// 可变List
List<String> mutableList = new ArrayList<>(Arrays.asList(array));
Java 8+ Stream方式
List<String> list = Arrays.stream(array).collect(Collectors.toList());// 去重
Set<String> set = Arrays.stream(array).collect(Collectors.toSet());
六、集合框架底层实现
1. ArrayList实现原理
- 底层结构:动态数组
Object[] elementData
- 扩容机制:
- 默认初始容量10
- 扩容时
newCapacity = oldCapacity + (oldCapacity >> 1)
(约1.5倍) - 最大容量
Integer.MAX_VALUE - 8
- 特点:
- 随机访问快(O(1))
- 插入删除慢(平均O(n))
- 线程不安全
2. LinkedList实现原理
- 底层结构:双向链表
private static class Node<E> {E item;Node<E> next;Node<E> prev;// ... }
- 特点:
- 插入删除快(O(1))
- 随机访问慢(O(n))
- 实现了List和Deque接口
3. HashMap实现原理(Java 8+)
- 底层结构:数组+链表+红黑树
- 默认初始容量16,负载因子0.75
- 链表长度>8且数组长度≥64时,链表转红黑树
- 树节点数<6时,红黑树转链表
- 哈希计算:
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
- 扩容机制:
- 容量变为2倍
- 重新计算节点位置:
newTab[e.hash & (newCap - 1)]
4. TreeMap实现原理
- 底层结构:红黑树(自平衡二叉查找树)
- 排序规则:
- 自然排序(元素实现Comparable)
- 或通过Comparator自定义排序
- 特点:
- 查找、插入、删除时间复杂度O(log n)
- 保持元素有序
七、集合框架性能比较
1. List实现比较
操作 | ArrayList | LinkedList |
---|---|---|
get(int) | O(1) | O(n) |
add(E) | 平均O(1) | O(1) |
add(int, E) | O(n) | O(1) |
remove(int) | O(n) | O(1) |
内存占用 | 较小(仅数组) | 较大(节点开销) |
2. Set实现比较
特性 | HashSet | LinkedHashSet | TreeSet |
---|---|---|---|
底层实现 | HashMap | LinkedHashMap | TreeMap |
顺序 | 无序 | 插入顺序 | 自然/自定义排序 |
时间复杂度 | O(1) | O(1) | O(log n) |
线程安全 | 否 | 否 | 否 |
3. Map实现比较
特性 | HashMap | LinkedHashMap | TreeMap | Hashtable |
---|---|---|---|---|
底层实现 | 数组+链表+红黑树 | 链表+哈希表 | 红黑树 | 数组+链表 |
顺序 | 无序 | 插入/访问顺序 | 键排序 | 无序 |
线程安全 | 否 | 否 | 否 | 是 |
允许null | 是 | 是 | 否 | 否 |
八、线程安全集合
1. 传统线程安全集合
Vector和Hashtable
// 线程安全但性能较差
Vector<String> vector = new Vector<>();
Hashtable<String, Integer> hashtable = new Hashtable<>();
Collections.synchronizedXXX
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
2. Java 5+并发集合
CopyOnWriteArrayList
// 写时复制,适合读多写少场景
List<String> cowList = new CopyOnWriteArrayList<>();
ConcurrentHashMap
// 分段锁实现高并发
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
BlockingQueue
// 阻塞队列
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("item"); // 阻塞直到空间可用
String item = queue.take(); // 阻塞直到元素可用
九、最佳实践
1. 集合选择策略
- 需要快速随机访问:ArrayList
- 频繁插入删除:LinkedList
- 去重存储:HashSet/LinkedHashSet/TreeSet
- 键值存储:HashMap/LinkedHashMap/TreeMap
- 线程安全:ConcurrentHashMap/CopyOnWriteArrayList
2. 性能优化建议
-
初始化合适容量:
new ArrayList<>(100); // 避免频繁扩容 new HashMap<>(32, 0.75f);
-
使用forEach代替迭代器:
// Java 8+ list.forEach(System.out::println); map.forEach((k, v) -> System.out.println(k + ": " + v));
-
避免在循环中修改集合:
// 错误方式 - 可能抛出ConcurrentModificationException for (String item : list) {if (condition) {list.remove(item);} }// 正确方式 - 使用迭代器 Iterator<String> it = list.iterator(); while (it.hasNext()) {if (condition) {it.remove();} }
3. 常见陷阱
-
Arrays.asList返回固定大小List:
List<String> list = Arrays.asList("A", "B", "C"); // list.add("D"); // 抛出UnsupportedOperationException
-
集合元素可变性问题:
Set<Date> dates = new HashSet<>(); Date now = new Date(); dates.add(now); now.setTime(now.getTime() + 1000); // 修改后影响集合行为
-
equals和hashCode不一致:
class Person {String name;// 如果只重写equals不重写hashCode,会导致HashSet/HashMap行为异常 }
十、Java 8-17集合新特性
1. Java 8增强
- Stream API:函数式集合操作
- HashMap性能提升:链表转红黑树
- 新增方法:
map.computeIfAbsent(key, k -> new ArrayList<>()).add(value); list.removeIf(e -> e.length() > 5);
2. Java 9增强
- 工厂方法创建不可变集合:
List<String> list = List.of("A", "B", "C"); Set<Integer> set = Set.of(1, 2, 3); Map<String, Integer> map = Map.of("A", 1, "B", 2);
3. Java 10增强
- copyOf创建不可变集合:
List<String> copy = List.copyOf(originalList);
4. Java 16增强
- Stream.toList()简化:
List<String> list = stream.toList(); // 替代collect(Collectors.toList())
通过深入理解Java集合框架的设计原理和使用方法,开发者可以编写出更高效、更健壮的代码。集合框架是Java编程中最常用的工具之一,掌握其特性和最佳实践对提高开发效率至关重要。