Java Collection 包使用指南

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 线程安全

  • 单线程环境:使用普通集合
  • 多线程环境:
    • 读多写少:使用 CopyOnWriteArrayListCopyOnWriteArraySet
    • 高并发:使用 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应用至关重要。选择合适的集合类型,遵循最佳实践,可以显著提升代码质量和性能。希望这份指南对你有所帮助!

相关推荐
Hero | 柒3 小时前
设计模式之单例模式
java·单例模式·设计模式
哈哈哈哈~3 小时前
Java中的单例模式
java·单例模式
纪莫3 小时前
技术面:Spring(循环依赖,spring与springboot的区别)
java·spring·java面试⑧股
oak隔壁找我3 小时前
Spring Boot MongoDB 使用技巧
java·后端
嫄码4 小时前
BigDecimal对象比较时的注意事项
java
倚栏听风雨4 小时前
RAG检索增强生成(Retrieval Augmented Generation)
后端
我是华为OD~HR~栗栗呀4 小时前
华为OD-23届考研-测试面经
java·c++·python·华为od·华为·面试·单元测试
敲代码的嘎仔4 小时前
JavaWeb零基础学习Day4——Maven
java·开发语言·学习·算法·maven·javaweb·学习方法