1. Java集合框架概述
Java集合框架(Java Collections Framework)是Java语言中用于存储和操作数据集合的一组接口和实现类。它位于java.util包中,提供了一套标准化的数据结构实现,包括列表、集合、队列和映射等。作为Java开发者日常工作中最常用的工具之一,集合框架的掌握程度直接影响着代码的质量和性能。
我第一次深入接触Java集合是在处理一个电商平台的商品列表时。当时使用简单的数组存储商品数据,随着业务增长,频繁的插入、删除操作导致性能急剧下降。改用ArrayList后,不仅代码更简洁,性能也提升了数倍。这个经历让我深刻认识到集合框架的重要性。
Java集合框架主要分为两大类:
- Collection接口:表示一组对象,包括List、Set和Queue等子接口
- Map接口:表示键值对映射,不是Collection的子接口但属于集合框架
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心集合接口详解
2.1 List接口及其实现
List是有序集合,允许重复元素。最常见的实现类有:
- ArrayList:基于动态数组实现,适合随机访问但不适合频繁插入删除
java复制List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
System.out.println(arrayList.get(0)); // 输出"Java"
- LinkedList:基于双向链表实现,适合频繁插入删除但随机访问性能较差
java复制List<Integer> linkedList = new LinkedList<>();
linkedList.add(1);
linkedList.addFirst(0); // 在头部插入
- Vector:线程安全的动态数组实现,但性能较差,已被ArrayList取代
提示:在已知元素数量且不需要修改的情况下,使用Arrays.asList()可以创建固定大小的列表
2.2 Set接口及其实现
Set是不允许重复元素的集合,主要实现类包括:
- HashSet:基于哈希表实现,无序但查询性能最好
java复制Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Apple"); // 重复元素不会被添加
- LinkedHashSet:维护插入顺序的HashSet
java复制Set<Integer> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(3);
linkedHashSet.add(1);
linkedHashSet.add(2);
// 遍历顺序保证为3,1,2
- TreeSet:基于红黑树实现,元素自动排序
java复制Set<String> treeSet = new TreeSet<>();
treeSet.add("Orange");
treeSet.add("Apple");
// 遍历顺序为"Apple","Orange"
2.3 Map接口及其实现
Map存储键值对,主要实现类有:
- HashMap:基于哈希表实现,允许null键值
java复制Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Java", 1995);
hashMap.put("Python", 1991);
- LinkedHashMap:维护插入顺序的HashMap
java复制Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("First", 1);
linkedHashMap.put("Second", 2);
// 遍历顺序与插入顺序一致
- TreeMap:基于红黑树实现,按键排序
java复制Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("B", 2);
treeMap.put("A", 1);
// 遍历顺序为"A","B"
- ConcurrentHashMap:线程安全的HashMap实现
3. 集合的线程安全问题
3.1 非线程安全集合的风险
大多数集合实现(如ArrayList、HashMap)不是线程安全的。在多线程环境下直接使用可能导致:
- 数据不一致
- ConcurrentModificationException
- 无限循环等严重问题
3.2 线程安全解决方案
- 使用Collections工具类同步包装
java复制List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
- 使用并发集合类
java复制ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
CopyOnWriteArrayList<String> copyOnWriteList = new CopyOnWriteArrayList<>();
- 使用不可变集合(Java 9+)
java复制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);
注意:同步包装集合的性能较差,在高并发场景下优先考虑并发集合类
4. Java 8对集合的增强
4.1 Stream API
Stream API为集合操作提供了函数式编程支持:
java复制List<String> languages = Arrays.asList("Java", "Python", "C++", "JavaScript");
// 过滤和收集
List<String> filtered = languages.stream()
.filter(lang -> lang.startsWith("J"))
.collect(Collectors.toList());
// 映射
List<Integer> lengths = languages.stream()
.map(String::length)
.collect(Collectors.toList());
// 排序
List<String> sorted = languages.stream()
.sorted()
.collect(Collectors.toList());
4.2 Lambda表达式支持
集合操作可以结合Lambda表达式变得更简洁:
java复制List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用forEach
numbers.forEach(n -> System.out.println(n));
// 使用removeIf
numbers.removeIf(n -> n % 2 == 0);
4.3 新的集合工厂方法(Java 9+)
Java 9引入了更简洁的集合创建方式:
java复制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);
5. 集合性能优化实践
5.1 选择合适的集合类型
- 需要快速随机访问 → ArrayList
- 频繁插入删除 → LinkedList
- 需要去重 → HashSet
- 需要排序 → TreeSet
- 键值存储 → HashMap
- 需要有序键值 → LinkedHashMap
5.2 初始化容量优化
对于已知大小的集合,指定初始容量避免扩容开销:
java复制// 已知大约有1000个元素
List<String> list = new ArrayList<>(1000);
Map<String, Integer> map = new HashMap<>(1024);
5.3 避免装箱拆箱
对于基本类型,考虑使用专门集合类:
java复制// 使用IntStream而不是Stream<Integer>
IntStream.range(0, 100).sum();
// 使用Eclipse Collections等第三方库
IntList intList = IntLists.mutable.of(1, 2, 3);
5.4 并行流使用注意事项
并行流不一定总是更快,需要考虑:
- 数据量(通常>1万元素才考虑)
- 操作复杂度(简单操作可能得不偿失)
- 线程安全(确保操作无状态)
java复制// 适合并行的情况
long count = largeList.parallelStream()
.filter(s -> s.length() > 10)
.count();
6. 集合常见问题与解决方案
6.1 ConcurrentModificationException
遍历时修改集合会抛出此异常:
错误示例:
java复制List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String s : list) {
if (s.equals("B")) {
list.remove(s); // 抛出异常
}
}
解决方案:
- 使用迭代器的remove方法
java复制Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("B")) {
it.remove(); // 安全删除
}
}
- 使用Java 8的removeIf
java复制list.removeIf(s -> s.equals("B"));
- 创建副本进行修改
java复制new ArrayList<>(list).forEach(s -> {
if (s.equals("B")) {
list.remove(s);
}
});
6.2 内存泄漏风险
集合可能无意中持有对象引用导致内存泄漏:
java复制Map<Key, Value> map = new HashMap<>();
Key key = new Key();
map.put(key, new Value());
// 即使key不再需要,map仍然持有引用
key = null; // key对象不会被GC回收
解决方案:
- 使用WeakHashMap
- 及时清理不再使用的集合
- 使用软引用/弱引用集合
6.3 集合元素比较问题
自定义对象作为集合元素时需要正确实现equals和hashCode:
java复制class Person {
String name;
int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
7. 高级集合应用场景
7.1 多级集合处理
处理嵌套集合时的最佳实践:
java复制Map<String, List<Student>> classMap = new HashMap<>();
// 使用computeIfAbsent避免空检查
classMap.computeIfAbsent("ClassA", k -> new ArrayList<>())
.add(new Student("Alice"));
// 使用flatMap处理嵌套集合
List<Student> allStudents = classMap.values().stream()
.flatMap(List::stream)
.collect(Collectors.toList());
7.2 自定义集合实现
扩展Abstract类创建自定义集合:
java复制class CaseInsensitiveSet extends AbstractSet<String> {
private final Set<String> delegate = new HashSet<>();
@Override
public boolean add(String s) {
return delegate.add(s.toLowerCase());
}
@Override
public boolean contains(Object o) {
return o instanceof String &&
delegate.contains(((String) o).toLowerCase());
}
@Override
public Iterator<String> iterator() {
return delegate.iterator();
}
@Override
public int size() {
return delegate.size();
}
}
7.3 集合与数组转换
集合与数组之间的高效转换:
java复制// 集合转数组
List<String> list = Arrays.asList("A", "B", "C");
String[] array = list.toArray(new String[0]);
// 数组转集合(Java 9+)
List<String> newList = List.of(array);
// 注意:Arrays.asList()返回的是固定大小列表
List<String> fixedList = Arrays.asList("A", "B", "C");
fixedList.add("D"); // 抛出UnsupportedOperationException
8. Java集合面试重点
8.1 常见面试问题
- ArrayList和LinkedList的区别?
- HashMap的工作原理?
- ConcurrentHashMap如何实现线程安全?
- 如何设计一个LRU缓存?
- Java集合的快速失败(fail-fast)和安全失败(fail-safe)机制?
8.2 HashMap深度解析
HashMap是面试中最常问的集合类,关键点包括:
- 哈希函数设计
- 解决哈希冲突的方法(链表和红黑树)
- 扩容机制和负载因子
- Java 8的优化(树化阈值)
java复制// HashMap初始化参数示例
Map<String, Integer> map = new HashMap<>(16, 0.75f);
// 初始容量16,负载因子0.75
8.3 集合工具类使用
Collections工具类提供多种实用方法:
java复制List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);
// 排序
Collections.sort(numbers);
// 二分查找(必须先排序)
int index = Collections.binarySearch(numbers, 4);
// 不可变包装
List<Integer> unmodifiable = Collections.unmodifiableList(numbers);
// 同步包装
List<Integer> synchronizedList = Collections.synchronizedList(numbers);
在实际项目中,我经常遇到需要根据业务场景选择合适集合的情况。比如在处理高并发缓存时,ConcurrentHashMap的性能通常比同步的HashMap好很多;而在处理需要保持插入顺序的键值对时,LinkedHashMap是不二之选。理解每种集合的内部实现原理,才能在各种场景下做出最优选择。
