当前位置: 首页 > web >正文

(十九)Java集合框架深度解析:从基础到高级应用

一、集合框架概述

1.1 什么是集合框架

Java集合框架(Java Collections Framework, JCF)是Java语言中用于表示和操作集合的一套标准化体系结构。它提供了一组接口、实现类和算法,用于存储和操作对象组,解决了数组在存储对象时的诸多限制。

集合框架的主要优势包括:

  • 减少编程工作量:提供通用的数据结构和算法

  • 提高程序性能:经过优化的实现

  • 促进API互操作性:统一的接口规范

  • 降低学习成本:一致的架构设计

  • 提高软件质量:经过充分测试的代码

1.2 集合框架的体系结构

Java集合框架主要由以下几部分组成:

  1. 接口:定义集合的抽象数据类型

  2. 实现:接口的具体实现类

  3. 算法:对集合进行操作的方法,如排序、搜索等

集合框架的核心接口层次结构如下:

Iterable
└── Collection├── List├── Set│   └── SortedSet└── Queue└── Deque

此外还有独立的Map接口及其子接口SortedMap

1.3 集合框架的历史演变

Java集合框架经历了几个重要的发展阶段:

  • JDK 1.0:只有Vector、Hashtable等简单集合类

  • JDK 1.2:引入完整的集合框架

  • JDK 1.5:加入泛型支持

  • JDK 1.6:性能优化和小幅API增强

  • JDK 1.7:引入钻石操作符等语法糖

  • JDK 1.8:加入Stream API和Lambda表达式支持

  • JDK 9:新增不可变集合工厂方法

  • JDK 10:引入var类型推断

  • JDK 11+:持续优化和增强

二、核心接口详解

2.1 Collection接口

Collection是集合框架的根接口,定义了所有集合共有的基本操作:

java

public interface Collection<E> extends Iterable<E> {// 基本操作int size();boolean isEmpty();boolean contains(Object element);boolean add(E element);boolean remove(Object element);Iterator<E> iterator();// 批量操作boolean containsAll(Collection<?> c);boolean addAll(Collection<? extends E> c);boolean removeAll(Collection<?> c);boolean retainAll(Collection<?> c);void clear();// 数组操作Object[] toArray();<T> T[] toArray(T[] a);// JDK 8新增的默认方法default boolean removeIf(Predicate<? super E> filter) { ... }default Spliterator<E> spliterator() { ... }default Stream<E> stream() { ... }default Stream<E> parallelStream() { ... }
}

2.2 List接口

List是有序集合(也称为序列),允许重复元素和null值。主要特点包括:

  • 精确控制每个元素的插入位置

  • 可以通过索引访问元素

  • 可以搜索元素

  • 允许对列表进行迭代

java

public interface List<E> extends Collection<E> {// 位置访问操作E get(int index);E set(int index, E element);void add(int index, E element);E remove(int index);int indexOf(Object o);int lastIndexOf(Object o);// 列表迭代器ListIterator<E> listIterator();ListIterator<E> listIterator(int index);// 范围视图List<E> subList(int fromIndex, int toIndex);// JDK 8新增的默认方法default void replaceAll(UnaryOperator<E> operator) { ... }default void sort(Comparator<? super E> c) { ... }
}

2.3 Set接口

Set是不包含重复元素的集合,最多包含一个null元素。它模拟了数学上的集合概念,不保证元素的顺序(除非使用SortedSet)。

java

public interface Set<E> extends Collection<E> {// 从Collection继承的方法// JDK 8新增的默认方法default Spliterator<E> spliterator() { ... }
}

2.4 Queue接口

Queue是一种特殊的集合,用于在处理前保存元素。队列通常(但不一定)以FIFO(先进先出)方式排序元素。

java

public interface Queue<E> extends Collection<E> {// 插入操作boolean add(E e);boolean offer(E e);// 移除操作E remove();E poll();// 检查操作E element();E peek();
}

2.5 Map接口

Map不是真正的集合(不继承Collection接口),但完全集成在集合框架中。它将键映射到值,键不能重复,每个键最多映射到一个值。

java

public interface Map<K,V> {// 基本操作int size();boolean isEmpty();boolean containsKey(Object key);boolean containsValue(Object value);V get(Object key);V put(K key, V value);V remove(Object key);void putAll(Map<? extends K, ? extends V> m);void clear();// 集合视图Set<K> keySet();Collection<V> values();Set<Map.Entry<K, V>> entrySet();// 内部Entry接口interface Entry<K,V> {K getKey();V getValue();V setValue(V value);boolean equals(Object o);int hashCode();// JDK 8新增的默认方法public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() { ... }public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() { ... }}// JDK 8新增的默认方法default V getOrDefault(Object key, V defaultValue) { ... }default void forEach(BiConsumer<? super K, ? super V> action) { ... }default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { ... }default V putIfAbsent(K key, V value) { ... }default boolean remove(Object key, Object value) { ... }default boolean replace(K key, V oldValue, V newValue) { ... }default V replace(K key, V value) { ... }default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) { ... }default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { ... }default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) { ... }default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { ... }
}

三、主要实现类分析

3.1 List实现类

3.1.1 ArrayList

基于动态数组的实现,非线程安全。特点:

  • 随机访问快(O(1))

  • 尾部插入删除快(O(1))

  • 中间插入删除慢(O(n))

  • 内存占用较少

java

// 典型使用场景
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add(1, "C++"); // 在索引1处插入// 遍历方式
for (String s : list) {System.out.println(s);
}// JDK 8+的forEach方法
list.forEach(System.out::println);
3.1.2 LinkedList

基于双向链表的实现,同时实现了List和Deque接口。特点:

  • 任意位置插入删除快(O(1))

  • 随机访问慢(O(n))

  • 内存占用较多(需要存储前后节点引用)

java

// 典型使用场景
List<Integer> linkedList = new LinkedList<>();
linkedList.add(10);
linkedList.addFirst(5); // 作为Deque使用
linkedList.addLast(15); // 作为Deque使用// 迭代器遍历
Iterator<Integer> it = linkedList.iterator();
while (it.hasNext()) {System.out.println(it.next());
}
3.1.3 Vector

线程安全的动态数组实现,方法都使用synchronized修饰。已逐渐被ArrayList和Collections.synchronizedList取代。

java

// 使用示例
Vector<String> vector = new Vector<>();
vector.add("Old");
vector.add("Collection");
3.1.4 CopyOnWriteArrayList

线程安全的List实现,适合读多写少的场景。所有修改操作都会创建底层数组的新副本。

java

// 使用示例
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();
cowList.add("Thread-safe");
cowList.add("List");

3.2 Set实现类

3.2.1 HashSet

基于HashMap实现的Set,使用对象的hashCode()方法确定元素位置。特点:

  • 元素无序

  • 添加、删除、包含操作都是O(1)

  • 允许null元素

java

// 使用示例
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复元素不会被添加System.out.println(set.contains("Apple")); // true
3.2.2 LinkedHashSet

继承自HashSet,但同时维护了一个双向链表来保持插入顺序。特点:

  • 迭代顺序可预测

  • 性能略低于HashSet

  • 适合需要保持插入顺序的场景

java

// 使用示例
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("First");
linkedHashSet.add("Second");
linkedHashSet.add("Third");// 遍历时会按照插入顺序输出
linkedHashSet.forEach(System.out::println);
3.2.3 TreeSet

基于TreeMap实现的NavigableSet,元素按照自然顺序或Comparator排序。特点:

  • 元素有序

  • 添加、删除、包含操作都是O(log n)

  • 不允许null元素(除非Comparator允许)

java

// 使用示例
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(5);
treeSet.add(2);
treeSet.add(8);// 遍历时会按照自然顺序输出
treeSet.forEach(System.out::println); // 输出 2,5,8
3.2.4 CopyOnWriteArraySet

基于CopyOnWriteArrayList实现的线程安全Set,适合读多写少的场景。

java

// 使用示例
CopyOnWriteArraySet<String> cowSet = new CopyOnWriteArraySet<>();
cowSet.add("Thread-safe");
cowSet.add("Set");
3.2.5 EnumSet

专为枚举类型设计的高性能Set实现,内部使用位向量表示。

java

// 使用示例
enum Day { MONDAY, TUESDAY, WEDNESDAY }
EnumSet<Day> days = EnumSet.of(Day.MONDAY, Day.WEDNESDAY);

3.3 Queue实现类

3.3.1 LinkedList

如前所述,LinkedList也实现了Deque接口,因此可以作为队列使用。

java

// 作为队列使用
Queue<String> queue = new LinkedList<>();
queue.offer("First");
queue.offer("Second");
String first = queue.poll(); // 移除并返回头部元素
3.3.2 PriorityQueue

基于优先级堆的无界优先级队列,元素按照自然顺序或Comparator排序。

java

// 使用示例
Queue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(5);
priorityQueue.offer(1);
priorityQueue.offer(3);// 出队顺序是1,3,5
while (!priorityQueue.isEmpty()) {System.out.println(priorityQueue.poll());
}
3.3.3 ArrayDeque

基于循环数组实现的双端队列,比LinkedList更高效。适合用作栈或队列。

java

// 作为栈使用
Deque<String> stack = new ArrayDeque<>();
stack.push("First");
stack.push("Second");
String top = stack.pop(); // "Second"// 作为队列使用
Deque<String> queue = new ArrayDeque<>();
queue.offer("First");
queue.offer("Second");
String first = queue.poll(); // "First"
3.3.4 BlockingQueue实现

java.util.concurrent包提供了多种阻塞队列实现:

  • ArrayBlockingQueue:有界阻塞队列

  • LinkedBlockingQueue:可选有界阻塞队列

  • PriorityBlockingQueue:无界优先级阻塞队列

  • SynchronousQueue:不存储元素的阻塞队列

  • DelayQueue:元素延迟到期的无界阻塞队列

java

// 使用示例
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10);
// 生产者线程
new Thread(() -> {try {blockingQueue.put("Message");} catch (InterruptedException e) {Thread.currentThread().interrupt();}
}).start();// 消费者线程
new Thread(() -> {try {String message = blockingQueue.take();System.out.println("Received: " + message);} catch (InterruptedException e) {Thread.currentThread().interrupt();}
}).start();

3.4 Map实现类

3.4.1 HashMap

基于哈希表的Map实现,允许null键和null值。特点:

  • 键无序

  • 基本操作时间复杂度为O(1)

  • 初始容量和负载因子影响性能

java

// 使用示例
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 25);
map.put("Bob", 30);
map.put("Charlie", 28);// 获取值
int age = map.get("Bob"); // 30// 遍历
map.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));
3.4.2 LinkedHashMap

继承自HashMap,同时维护了一个双向链表来保持插入顺序或访问顺序。特点:

  • 可以预测的迭代顺序

  • 性能略低于HashMap

  • 适合需要保持插入/访问顺序的场景

java

// 保持插入顺序
Map<String, Integer> linkedMap = new LinkedHashMap<>();
linkedMap.put("First", 1);
linkedMap.put("Second", 2);
linkedMap.put("Third", 3);// 遍历顺序与插入顺序一致
linkedMap.forEach((k, v) -> System.out.println(k));// 创建LRU缓存
Map<String, Integer> lruCache = new LinkedHashMap<>(16, 0.75f, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {return size() > 3;}
};
3.4.3 TreeMap

基于红黑树实现的NavigableMap,键按照自然顺序或Comparator排序。特点:

  • 键有序

  • 基本操作时间复杂度为O(log n)

  • 不允许null键(除非Comparator允许)

java

// 使用示例
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Orange", 2);
treeMap.put("Apple", 5);
treeMap.put("Banana", 3);// 遍历顺序是Apple, Banana, Orange
treeMap.forEach((fruit, count) -> System.out.println(fruit + ": " + count));
3.4.4 Hashtable

线程安全的Map实现,方法都使用synchronized修饰。已逐渐被HashMap和ConcurrentHashMap取代。

java

// 使用示例
Hashtable<String, Integer> table = new Hashtable<>();
table.put("One", 1);
table.put("Two", 2);
3.4.5 ConcurrentHashMap

线程安全的高性能HashMap实现,使用分段锁技术(JDK 8后改为CAS+synchronized)。特点:

  • 高并发性能

  • 不允许null键和null值

  • 操作通常不需要锁定整个表

java

// 使用示例
ConcurrentMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("Key1", 1);
concurrentMap.putIfAbsent("Key1", 2); // 不会替换已有值// 原子更新
concurrentMap.compute("Key1", (k, v) -> v == null ? 0 : v + 1);
3.4.6 EnumMap

专为枚举键设计的Map实现,内部使用数组存储,非常紧凑和高效。

java

// 使用示例
enum Day { MONDAY, TUESDAY, WEDNESDAY }
Map<Day, String> enumMap = new EnumMap<>(Day.class);
enumMap.put(Day.MONDAY, "First day");
3.4.7 IdentityHashMap

使用==而不是equals比较键的Map实现,适合需要对象标识而非对象值相等的场景。

java

// 使用示例
Map<String, Integer> identityMap = new IdentityHashMap<>();
String key1 = new String("key");
String key2 = new String("key");
identityMap.put(key1, 1);
identityMap.put(key2, 2); // 两个不同的键
System.out.println(identityMap.size()); // 2
3.4.8 WeakHashMap

使用弱引用作为键的Map实现,当键不再被普通引用时,条目会被自动移除。适合实现缓存。

java

// 使用示例
Map<Object, String> weakMap = new WeakHashMap<>();
Object key = new Object();
weakMap.put(key, "value");
key = null; // 使键只被弱引用持有
System.gc(); // 垃圾回收后,条目可能会被移除

四、集合工具类

4.1 Collections工具类

java.util.Collections提供了大量静态方法,用于操作或返回集合。

4.1.1 排序和搜索

java

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);// 排序
Collections.sort(numbers); // [1, 1, 3, 4, 5, 9]// 自定义排序
Collections.sort(numbers, Comparator.reverseOrder()); // [9, 5, 4, 3, 1, 1]// 二分查找(列表必须已排序)
int index = Collections.binarySearch(numbers, 4); // 2// 随机打乱
Collections.shuffle(numbers);
4.1.2 不可变集合

java

// 创建不可变集合
List<String> immutableList = Collections.unmodifiableList(new ArrayList<>());
Set<Integer> immutableSet = Collections.unmodifiableSet(new HashSet<>());
Map<String, Integer> immutableMap = Collections.unmodifiableMap(new HashMap<>());// JDK 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);
4.1.3 同步集合

java

// 创建线程安全集合
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<Integer> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
4.1.4 其他实用方法

java

// 填充
List<String> list = new ArrayList<>(Collections.nCopies(3, "default"));
Collections.fill(list, "new"); // ["new", "new", "new"]// 频率统计
int freq = Collections.frequency(list, "new"); // 3// 极值
Integer max = Collections.max(numbers);
Integer min = Collections.min(numbers);// 替换所有
Collections.replaceAll(list, "new", "old");// 反转
Collections.reverse(list);// 旋转(将后两个元素移到前面)
Collections.rotate(list, 2);

4.2 Arrays工具类

java.util.Arrays提供了操作数组的实用方法,许多方法与Collections类似。

java

// 数组转List(返回的List是固定大小的)
List<String> list = Arrays.asList("a", "b", "c");// 排序
int[] numbers = {3, 1, 4, 1, 5, 9};
Arrays.sort(numbers); // [1, 1, 3, 4, 5, 9]// 二分查找
int index = Arrays.binarySearch(numbers, 4); // 3// 填充
Arrays.fill(numbers, 0); // [0, 0, 0, 0, 0, 0]// 比较
int[] copy = Arrays.copyOf(numbers, numbers.length);
boolean equal = Arrays.equals(numbers, copy); // true// 字符串表示
String str = Arrays.toString(numbers); // "[0, 0, 0, 0, 0, 0]"// 并行排序(大数据量时性能更好)
Arrays.parallelSort(new int[] {5, 3, 9, 1});// JDK 8新增的Stream支持
int sum = Arrays.stream(numbers).sum();

五、集合的迭代与遍历

5.1 迭代器模式

Java集合框架基于迭代器模式,提供了一种统一的方法来遍历各种集合。

5.1.1 Iterator接口

java

public interface Iterator<E> {boolean hasNext();E next();default void remove() { throw new UnsupportedOperationException(); }default void forEachRemaining(Consumer<? super E> action) { ... }
}

基本用法:

java

List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> it = list.iterator();
while (it.hasNext()) {String element = it.next();System.out.println(element);if (element.equals("B")) {it.remove(); // 移除当前元素}
}
5.1.2 ListIterator接口

ListIterator扩展了Iterator,支持双向遍历和修改操作。

java

public interface ListIterator<E> extends Iterator<E> {boolean hasNext();E next();boolean hasPrevious();E previous();int nextIndex();int previousIndex();void remove();void set(E e);void add(E e);
}

使用示例:

java

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
ListIterator<String> lit = list.listIterator();// 正向遍历
while (lit.hasNext()) {System.out.println(lit.next());
}// 反向遍历
while (lit.hasPrevious()) {String element = lit.previous();System.out.println(element);if (element.equals("B")) {lit.set("B-Updated"); // 修改当前元素}
}
5.1.3 快速失败(fail-fast)机制

大多数集合的迭代器实现了快速失败机制,当在迭代过程中检测到集合被修改(除了通过迭代器自己的remove方法),会抛出ConcurrentModificationException

java

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));// 会抛出ConcurrentModificationException
for (String s : list) {if (s.equals("B")) {list.remove(s); // 错误的方式}
}// 正确的修改方式
Iterator<String> it = list.iterator();
while (it.hasNext()) {if (it.next().equals("B")) {it.remove(); // 通过迭代器移除}
}

5.2 遍历集合的各种方式

5.2.1 传统的for循环(适合List)

java

List<String> list = Arrays.asList("A", "B", "C");
for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));
}
5.2.2 增强的for-each循环

java

for (String s : list) {System.out.println(s);
}
5.2.3 使用Iterator

java

Iterator<String> it = list.iterator();
while (it.hasNext()) {System.out.println(it.next());
}
5.2.4 使用ListIterator

java

ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {System.out.println(lit.next());
}
5.2.5 使用Java 8的forEach方法

java

list.forEach(System.out::println);// 或使用Lambda表达式
list.forEach(s -> System.out.println(s));
5.2.6 使用Stream API

java

list.stream().forEach(System.out::println);// 并行处理
list.parallelStream().forEach(System.out::println);

5.3 Spliterator接口

JDK 8引入的Spliterator(可分迭代器)用于并行遍历和分割元素序列。

java

public interface Spliterator<T> {boolean tryAdvance(Consumer<? super T> action);Spliterator<T> trySplit();long estimateSize();int characteristics();
}

使用示例:

java

List<String> list = Arrays.asList("A", "B", "C", "D", "E");
Spliterator<String> spliterator = list.spliterator();// 尝试分割
Spliterator<String> half = spliterator.trySplit();// 处理前半部分
half.forEachRemaining(System.out::println); // 输出 A, B// 处理后半部分
spliterator.forEachRemaining(System.out::println); // 输出 C, D, E

六、集合的性能比较与选择

6.1 主要集合类的性能特征

集合类型实现类获取插入/删除包含有序线程安全允许null
ListArrayListO(1)O(n)O(n)插入顺序
ListLinkedListO(n)O(1)O(n)插入顺序
ListVectorO(1)O(n)O(n)插入顺序
SetHashSetO(1)O(1)O(1)是(1个)
SetLinkedHashSetO(1)O(1)O(1)插入顺序是(1个)
SetTreeSetO(log n)O(log n)O(log n)排序顺序
QueuePriorityQueueO(1) peekO(log n) offer-排序顺序
MapHashMapO(1)O(1)O(1)是(1个键)
MapLinkedHashMapO(1)O(1)O(1)插入/访问顺序是(1个键)
MapTreeMapO(log n)O(log n)O(log n)排序顺序否(键)
MapHashtableO(1)O(1)O(1)
MapConcurrentHashMapO(1)O(1)O(1)

6.2 如何选择合适的集合

选择集合时应考虑以下因素:

  1. 元素是否需要有序

    • 需要保持插入顺序:LinkedHashSet、LinkedHashMap、ArrayList、LinkedList

    • 需要排序:TreeSet、TreeMap、PriorityQueue

    • 不需要顺序:HashSet、HashMap

  2. 是否需要允许重复元素

    • 允许重复:List及其实现类

    • 不允许重复:Set及其实现类

  3. 性能需求

    • 随机访问多:ArrayList

    • 插入删除多:LinkedList

    • 快速查找:HashSet/HashMap

  4. 线程安全需求

    • 需要线程安全:ConcurrentHashMap、CopyOnWriteArrayList、Collections.synchronizedXxx

    • 不需要线程安全:标准实现类

  5. null值处理

    • 需要存储null:ArrayList、HashSet、HashMap等

    • 不能存储null:Hashtable、ConcurrentHashMap、EnumSet/Map等

  6. 内存占用

    • 内存敏感:ArrayList比LinkedList更节省空间

    • EnumSet/Map非常紧凑高效

6.3 集合初始容量与负载因子

对于基于哈希表的集合(HashMap、HashSet等),初始容量和负载因子影响性能:

  • 初始容量:哈希表创建时的桶数量。默认16。

  • 负载因子:哈希表自动扩容前的填充比例。默认0.75。

java

// 自定义初始容量和负载因子
Map<String, Integer> map = new HashMap<>(32, 0.5f);

合理设置这些参数可以减少rehash操作,提高性能:

  • 如果知道元素数量,设置初始容量为预期数量的1.33倍(1/0.75)

  • 高负载因子减少内存使用但增加查找成本

  • 低负载因子提高查找性能但增加内存使用

七、Java 8/9/10对集合的增强

7.1 Java 8的增强

7.1.1 Stream API

Stream API为集合提供了强大的数据操作能力:

java

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");// 过滤和映射
List<String> result = names.stream().filter(name -> name.length() > 4).map(String::toUpperCase).collect(Collectors.toList());// 统计
long count = names.stream().filter(name -> name.startsWith("A")).count();// 并行处理
int totalLength = names.parallelStream().mapToInt(String::length).sum();
7.1.2 forEach方法

所有集合都新增了forEach方法:

java

Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);// 遍历Map
map.forEach((k, v) -> System.out.println(k + "=" + v));
7.1.3 Map的增强方法

Map接口新增了许多实用方法:

java

Map<String, Integer> map = new HashMap<>();// 键不存在时才放入
map.putIfAbsent("A", 1);// 根据键计算新值
map.compute("A", (k, v) -> v == null ? 0 : v + 1);// 合并值
map.merge("A", 1, (oldVal, newVal) -> oldVal + newVal);// 获取或默认值
int val = map.getOrDefault("B", 0);
7.1.4 Collection的removeIf方法

java

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));// 移除所有偶数
numbers.removeIf(n -> n % 2 == 0); // [1, 3, 5]

7.2 Java 9的增强

7.2.1 不可变集合的工厂方法

Java 9引入了简洁的创建不可变集合的方法:

java

// 不可变List
List<String> immutableList = List.of("a", "b", "c");// 不可变Set
Set<Integer> immutableSet = Set.of(1, 2, 3);// 不可变Map
Map<String, Integer> immutableMap = Map.of("a", 1, "b", 2);// 更多元素的Map
Map<String, Integer> map = Map.ofEntries(Map.entry("a", 1),Map.entry("b", 2),Map.entry("c", 3)
);

这些集合:

  • 不允许null元素

  • 创建后不可修改

  • 空间优化(可能使用专用内部类)

7.2.2 其他增强
  • Optional增加了stream()方法

  • 新增Collectors.filteringCollectors.flatMapping

7.3 Java 10的增强

7.3.1 不可变集合的copyOf方法

java

List<String> original = new ArrayList<>();
List<String> copy = List.copyOf(original); // 不可变副本
7.3.2 var关键字与集合

虽然var不是集合特有的,但它简化了集合声明:

java

var list = new ArrayList<String>(); // 推断为ArrayList<String>
var map = new HashMap<Integer, String>(); // 推断为HashMap<Integer, String>

八、集合的最佳实践

8.1 通用最佳实践

  1. 使用接口类型声明集合

    java

    // 好
    List<String> list = new ArrayList<>();
    // 不好
    ArrayList<String> list = new ArrayList<>();

  2. 预估集合大小

    java

    // 如果知道大约需要存储1000个元素
    List<String> list = new ArrayList<>(1000);

  3. 使用isEmpty()而不是size()==0

    java

    // 好
    if (list.isEmpty()) { ... }
    // 不好
    if (list.size() == 0) { ... }

  4. 优先使用for-each循环

    java

    for (String s : list) { ... }

  5. 注意集合的equals和hashCode

    • 不同集合类的equals行为不同

    • 修改作为Map键的对象时要小心

8.2 并发场景下的最佳实践

  1. 选择合适的并发集合

    • 高并发读取:ConcurrentHashMap

    • 写少读多:CopyOnWriteArrayList

    • 阻塞队列:ArrayBlockingQueue

  2. 避免在迭代时修改集合

    • 使用并发集合或同步块

    • 或者先创建副本再迭代

  3. 注意原子复合操作

    java

    // 非原子操作
    if (!map.containsKey(key)) {map.put(key, value);
    }// 使用原子方法
    map.putIfAbsent(key, value);

8.3 性能优化建议

  1. 选择合适的集合类型

    • 随机访问多:ArrayList

    • 插入删除多:LinkedList

  2. 合理设置HashMap/HashSet初始容量

    java

    // 预期存储1000个元素,负载因子0.75
    Map<String, Integer> map = new HashMap<>(1333); // 1000 / 0.75

  3. 考虑使用EnumSet/EnumMap

    • 枚举集合非常高效

  4. 避免频繁的装箱拆箱

    • 考虑使用Trove、FastUtil等第三方库

  5. 批量操作优于单元素操作

    java

    // 好
    list.addAll(otherList);
    // 不好
    for (String s : otherList) {list.add(s);
    }

8.4 常见陷阱与避免方法

  1. ConcurrentModificationException

    • 避免在迭代时直接修改集合

    • 使用迭代器的remove方法或并发集合

  2. 可变对象作为Map键

    • 如果键对象可变,修改后可能导致找不到值

    • 建议使用不可变对象作为键

  3. equals和hashCode不一致

    • 确保相等的对象有相同的hashCode

    • 重写equals时必须重写hashCode

  4. 原始集合的泛型使用

    • 避免使用原始类型集合

    • 总是指定泛型参数

  5. 内存泄漏

    • 长期存活的集合可能导致内存泄漏

    • 考虑使用WeakHashMap或定期清理

九、集合框架的扩展与替代方案

9.1 第三方集合库

9.1.1 Google Guava

Google的Guava库提供了丰富的集合工具:

java

// 不可变集合
ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c");// 多值Map
Multimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.put

http://www.xdnf.cn/news/6514.html

相关文章:

  • Linux 内核核心知识热点题分析:10 个连环打通的难点
  • Modern C++(一)基本概念
  • 养生:健康生活的极简攻略
  • free void* 指令
  • list简单模拟实现
  • miniconda
  • 智能手表集成测试报告(Integration Test Report)
  • 磁盘性能测试与分析:结合fio和iostat的完整方案
  • muduo库中Channel模块的深度解析
  • LeetCode 3337.字符串转换后的长度 II:矩阵快速幂(也没有想象中的那么高级啦)
  • 小白上手RPM包制作
  • InforSuite RDS 与django结合
  • 21、工业大数据分析与实时告警 (模拟根因分析) - /数据与物联网组件/bigdata-root-cause-analysis
  • 创建你的第一个MCP服务
  • 【ROS2】ROS节点启动崩溃:rclcpp::exceptions::RCLInvalidArgument
  • Redis 大 key 问题解决方案
  • Windows软件插件-音视频捕获
  • 配置别名路径 @
  • 【落羽的落羽 C++】进一步认识模板
  • SpringBoot应用启动过程
  • 如何通过高防CDN让CC攻击有来无回?
  • 数学复习笔记 10
  • 鸿蒙OSUniApp 开发的文件上传与下载功能#三方框架 #Uniapp
  • CAPL编程系列_04
  • std::vector c++
  • LeetCode 热题 100 1.两数之和
  • 竞品分析是什么,包括哪些内容?AI竞品分析生成器推荐!
  • 20250515让飞凌的OK3588-C的核心板在Linux R4下适配以太网RTL8211F-CG为4线百兆时的接线图
  • VMware中快速安装与优化Ubuntu全攻略
  • 28、动画魔法圣典:Framer Motion 时空奥义全解——React 19 交互动效