Java Collection 包使用指南

1. Collection 框架概览

Java Collection 框架是一组用于存储和操作对象的接口和类,位于 java.util 包中。主要包括以下几个部分:

  • 接口层:定义各种集合的抽象数据类型
  • 实现层:提供各种接口的具体实现
  • 算法层:提供对集合进行操作的各种静态方法

2. 主要接口体系

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

// 创建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

// 创建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

// 创建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

// 创建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

// 创建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

// 创建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

// 创建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

// 创建优先队列(默认小顶堆)
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(双端队列)

// 创建双端队列
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

// 创建不可变集合
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+)

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 性能优化技巧

  • 初始化时指定集合大小,减少扩容开销
List<String> list = new ArrayList<>(100); // 预估大小
Map<String, Object> map = new HashMap<>(16, 0.75f); // 初始容量和负载因子
  • 遍历Map时使用entrySet而非keySet+get
// 推荐
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+)
// 更简洁、更高效
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);
  • 使用并行流处理大数据集(但需注意线程安全)
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)

// 创建不可变集合
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)

// 局部变量类型推断
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();

11.3 记录类与集合(Java 16+)

// 记录类作为集合元素更简洁
record Person(String name, int age) {}

List<Person> people = List.of(
    new Person("Alice", 30),
    new Person("Bob", 25)
);

掌握Java Collection框架的使用对于高效开发Java应用至关重要。选择合适的集合类型,遵循最佳实践,可以显著提升代码质量和性能。希望这份指南对你有所帮助!

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]