(十九)Java集合框架深度解析:从基础到高级应用
一、集合框架概述
1.1 什么是集合框架
Java集合框架(Java Collections Framework, JCF)是Java语言中用于表示和操作集合的一套标准化体系结构。它提供了一组接口、实现类和算法,用于存储和操作对象组,解决了数组在存储对象时的诸多限制。
集合框架的主要优势包括:
-
减少编程工作量:提供通用的数据结构和算法
-
提高程序性能:经过优化的实现
-
促进API互操作性:统一的接口规范
-
降低学习成本:一致的架构设计
-
提高软件质量:经过充分测试的代码
1.2 集合框架的体系结构
Java集合框架主要由以下几部分组成:
-
接口:定义集合的抽象数据类型
-
实现:接口的具体实现类
-
算法:对集合进行操作的方法,如排序、搜索等
集合框架的核心接口层次结构如下:
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 |
---|---|---|---|---|---|---|---|
List | ArrayList | O(1) | O(n) | O(n) | 插入顺序 | 否 | 是 |
List | LinkedList | O(n) | O(1) | O(n) | 插入顺序 | 否 | 是 |
List | Vector | O(1) | O(n) | O(n) | 插入顺序 | 是 | 是 |
Set | HashSet | O(1) | O(1) | O(1) | 无 | 否 | 是(1个) |
Set | LinkedHashSet | O(1) | O(1) | O(1) | 插入顺序 | 否 | 是(1个) |
Set | TreeSet | O(log n) | O(log n) | O(log n) | 排序顺序 | 否 | 否 |
Queue | PriorityQueue | O(1) peek | O(log n) offer | - | 排序顺序 | 否 | 否 |
Map | HashMap | O(1) | O(1) | O(1) | 无 | 否 | 是(1个键) |
Map | LinkedHashMap | O(1) | O(1) | O(1) | 插入/访问顺序 | 否 | 是(1个键) |
Map | TreeMap | O(log n) | O(log n) | O(log n) | 排序顺序 | 否 | 否(键) |
Map | Hashtable | O(1) | O(1) | O(1) | 无 | 是 | 否 |
Map | ConcurrentHashMap | O(1) | O(1) | O(1) | 无 | 是 | 否 |
6.2 如何选择合适的集合
选择集合时应考虑以下因素:
-
元素是否需要有序:
-
需要保持插入顺序:LinkedHashSet、LinkedHashMap、ArrayList、LinkedList
-
需要排序:TreeSet、TreeMap、PriorityQueue
-
不需要顺序:HashSet、HashMap
-
-
是否需要允许重复元素:
-
允许重复:List及其实现类
-
不允许重复:Set及其实现类
-
-
性能需求:
-
随机访问多:ArrayList
-
插入删除多:LinkedList
-
快速查找:HashSet/HashMap
-
-
线程安全需求:
-
需要线程安全:ConcurrentHashMap、CopyOnWriteArrayList、Collections.synchronizedXxx
-
不需要线程安全:标准实现类
-
-
null值处理:
-
需要存储null:ArrayList、HashSet、HashMap等
-
不能存储null:Hashtable、ConcurrentHashMap、EnumSet/Map等
-
-
内存占用:
-
内存敏感: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.filtering
和Collectors.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 通用最佳实践
-
使用接口类型声明集合:
java
// 好 List<String> list = new ArrayList<>(); // 不好 ArrayList<String> list = new ArrayList<>();
-
预估集合大小:
java
// 如果知道大约需要存储1000个元素 List<String> list = new ArrayList<>(1000);
-
使用isEmpty()而不是size()==0:
java
// 好 if (list.isEmpty()) { ... } // 不好 if (list.size() == 0) { ... }
-
优先使用for-each循环:
java
for (String s : list) { ... }
-
注意集合的equals和hashCode:
-
不同集合类的equals行为不同
-
修改作为Map键的对象时要小心
-
8.2 并发场景下的最佳实践
-
选择合适的并发集合:
-
高并发读取:
ConcurrentHashMap
-
写少读多:
CopyOnWriteArrayList
-
阻塞队列:
ArrayBlockingQueue
等
-
-
避免在迭代时修改集合:
-
使用并发集合或同步块
-
或者先创建副本再迭代
-
-
注意原子复合操作:
java
// 非原子操作 if (!map.containsKey(key)) {map.put(key, value); }// 使用原子方法 map.putIfAbsent(key, value);
8.3 性能优化建议
-
选择合适的集合类型:
-
随机访问多:ArrayList
-
插入删除多:LinkedList
-
-
合理设置HashMap/HashSet初始容量:
java
// 预期存储1000个元素,负载因子0.75 Map<String, Integer> map = new HashMap<>(1333); // 1000 / 0.75
-
考虑使用EnumSet/EnumMap:
-
枚举集合非常高效
-
-
避免频繁的装箱拆箱:
-
考虑使用Trove、FastUtil等第三方库
-
-
批量操作优于单元素操作:
java
// 好 list.addAll(otherList); // 不好 for (String s : otherList) {list.add(s); }
8.4 常见陷阱与避免方法
-
ConcurrentModificationException:
-
避免在迭代时直接修改集合
-
使用迭代器的remove方法或并发集合
-
-
可变对象作为Map键:
-
如果键对象可变,修改后可能导致找不到值
-
建议使用不可变对象作为键
-
-
equals和hashCode不一致:
-
确保相等的对象有相同的hashCode
-
重写equals时必须重写hashCode
-
-
原始集合的泛型使用:
-
避免使用原始类型集合
-
总是指定泛型参数
-
-
内存泄漏:
-
长期存活的集合可能导致内存泄漏
-
考虑使用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
相关文章:
(十九)Java集合框架深度解析:从基础到高级应用
一、集合框架概述 1.1 什么是集合框架 Java集合框架(Java Collections Framework, JCF)是Java语言中用于表示和操作集合的一套标准化体系结构。它提供了一组接口、实现类和算法,用于存储和操作对象组,解决了数组在存储对象时的诸多限制。 集合框架的主…...
数据结构与算法-线性表-单链表(Linked List)
1 线性表 1.2 单链表(Linked List) 顺序表在内存中是连续的进行存储,可以随机获取某个元素,但是在插入和删除元素的时候就非常不方便,需要移动很多相关的元素,链表就可以解决这个问题。 链表就是每个节点…...
Vue3学习(组合式API——生命周期函数基础)
目录 一、Vue3组合式API中的生命周期函数。 (1)各阶段生命周期涉及函数简单介绍。 <1>创建挂载阶段的生命周期函数。 <2>更新阶段的生命周期函数。 <3>卸载阶段的生命周期函数。 <4>错误处理的生命周期函数。 (2&…...
MySQL索引优化面试高频考点解析(附实战场景)
文章目录 当索引失效成为面试官的"送命题"(必看!)高频考点一:索引失效的七大死亡陷阱1. 隐式类型转换(血泪案例!)2. 函数操作毁所有 高频考点二:最左前缀原则的魔鬼细节组…...
三目云台20倍变焦智能监控技术
“三目云台20倍转动”通常指的是一种具备三目变焦功能和20倍光学变焦能力的云台摄像机。以下是对这一概念的详细解释: 一、三目变焦功能 三目云台摄像机通常配备“长、短、广”三组定焦镜头,每组镜头都有其独特的作用: 长焦镜头 ÿ…...
SQL注入---05--跨站注入
1 权限说明 select * from mysql.user; 这里的Y表示我前面的命令权限为root,n表示不支持root权限 导致结果: 如果为root的话,我就可操作这些命令并且可以进行跨数据库攻击,但是如果不是高权限root就无法执行这些操作 2 root权限…...
AAC 协议
1. ADTS(Audio Data Transport Stream)帧结构 在ADTS(Audio Data Transport Stream)帧结构中,“上面扩展28 bit”指的是ADTS固定头(adts_fixed_header())和ADTS可变头(adts_variable_header())各自包含的28位信息。 1.1 ADTS固定头(adts_fixed_header()) AAC 帧…...
HGDB企业版迁移到HGDB安全版
文章目录 环境文档用途详细信息 环境 系统平台:Linux x86-64 Red Hat Enterprise Linux 7 版本:4.5.8,6.0 文档用途 HGDB企业版数据库通过命令备份恢复,迁移到HGDB安全版中。 详细信息 1、环境介绍 1 IP 操作系统 cpux.x.65.10 …...
智慧化系统安全分析报告
智慧化系统的安全背景与现状 一、政策法规背景 (一)全球主要国家/地区政策对比 地区政策名称核心内容实施时间特点中国《生成式人工智能服务管理暂行办法》明确服务提供者责任,强调数据合法、隐私保护,禁止生成违法内容2023年8…...
概率相关问题
问题汇总 1. 贝叶斯定理(贝叶斯公式和全概率公式)2. 概率题2.1 随机发生器的概率为1/2 1. 贝叶斯定理(贝叶斯公式和全概率公式) 定义:在信息和条件有限的情况下,基于过去的数据,通过动态调整的…...
使用 GitDiagram 快速将 GitHub 仓库转换为交互式图表
前言 当面对 GitHub 上文件目录错综复杂的新项目,且你急需快速了解其系统设计或架构流程时,你可能会感到束手无策。今天大姚给大家分享一个开源利器 GitDiagram,它可以轻松将任何复杂的 GitHub 仓库转化为直观、交互式的图表,这对…...
AWS CloudHSM:金融级密钥安全管理实战,如何通过FIPS 140-2认证守护数据生命线?
数据泄露平均成本430万美元,加密漏洞成头号杀手!当《数据安全法》撞上金融科技合规,开发者如何用硬件安全模块(HSM)构建不可破解的密钥堡垒?本文揭秘AWS CloudHSM如何成为支付系统、电子病历、区块链的“数…...
自定义分区器-基础
什么是分区 在 Spark 里,弹性分布式数据集(RDD)是核心的数据抽象,它是不可变的、可分区的、里面的元素并行计算的集合。 在 Spark 中,分区是指将数据集按照一定的规则划分成多个较小的子集,每个子集可以独立…...
<C++> MFC自动关闭对话框(MessageBoxTimeout)
MFC自动关闭对话框(MessageBoxTimeout) 记录一下今天在界面开发中的解决方案。自动关闭对话框有两种方案: 1.使用定时器实现延迟关闭(DeepSeek方案) 提示框显示几秒后自动关闭,可以使用 SetTimer KillT…...
一个基于 Spring Boot 的实现,用于代理百度 AI 的 OCR 接口
一个基于 Spring Boot 的实现,用于代理百度 AI 的 OCR 接口 BaiduAIController.javaBaiduAIConfig.java在 application.yml 或 application.properties 中添加配置:application.yml同时,需要在Spring Boot应用中配置RestTemplate:…...
Python60日基础学习打卡D26
算圆形面积 错误代码 import mathdef calculate_circle_area(r):try:S math.pi * r**2except r<0:print("半径不能为负数")return S 正确代码 import mathdef calculate_circle_area(radius):try:if radius < 0:return 0return math.pi * radius…...
报销单业务笔记
文章目录 业务点业务点-对公对私业务点-多系统标志 特殊业务入参入参报文 出参出参报文中间的逻辑多对多关系 其他应该是整体成功还是可以部分成功这种多对多关多关系有没有优雅的判断方式 报销单是个通用场景,有通用逻辑,在此基础上进行适度定制&#x…...
小红书的评论区营销经验分享
在小红书等社交平台上采用“主账号提问小号解答”的营销策略,其核心作用是通过角色分工和场景化互动,降低用户对广告的抵触心理,同时提升内容的可信度和转化效率。以下是其底层逻辑和具体作用分析: 一、角色分工:制造…...
通义灵码 2.5.4 版【**编程智能体**】初体验
一、通义灵码安装 1.VSCode通义灵码插件安装 VSCode搜索lingma,出现Lingma-Alibaba,点击安装即可,安装完毕如下图所示。 可以看到右侧版本信息如下:alibaba-cloud.tongyi-lingma版本2.5.4上次更新时间2025-05-13, 11:02:16,安装…...
2025ICPC陕西省赛题解一
L. easy 每行选能选的最小的两个,注意处理奇数的情况。 #include <bits/stdc.h> #define x first #define y second #define int long longusing namespace std; typedef unsigned long long ULL ; typedef pair<int,int> PII ; typedef pair<lon…...
java方法的练习题
方法中对自定义类型的传递 package MethodParameter.MethodParameter03;public class MP03 {public static void main(String[] args) {Person p new Person();p.m_Age 100;p.m_Name "John";B b new B();b.test02(p);System.out.println(p.m_Age p.m_Name);} }…...
【在qiankun模式下el-dropdown点击,浏览器报Failed to execute ‘getComputedStyle‘ on ‘Window‘: parameter 1 is not o
在qiankun模式下el-dropdown点击,浏览器报Failed to execute ‘getComputedStyle’ on ‘Window’: parameter 1 is not of type ‘Element’ 错误 在qiankun模式下el-dropdown点击,浏览器报Failed to execute ‘getComputedStyle’ on ‘Window’: par…...
世界模型+大模型+自动驾驶 论文小汇总
最近看了一些论文,懒得一个个写博客了,直接汇总起来 文章目录 大模型VLM-ADVLM-E2EOpenDriveVLAFASIONAD:自适应反馈的类人自动驾驶中快速和慢速思维融合系统快系统慢系统快慢结合 世界模型End-to-End Driving with Online Trajectory Evalu…...
elementUI如何动态增减表单项
设置prop的字段::prop"configs.${i}.platform" <template><el-dialogtitle"编辑配置":close-on-click-modal"false":before-close"beforeClose":visible.sync"visible"v-if"visible"class&q…...
vite运行只能访问localhost解决办法
1、找到package.json的scripts方法 2、然后指定 vite --host即可...
msf安卓远控木马手动捆绑正常apk
生成的安卓木马捆绑到正常的apk的apk中可以增强隐蔽性,有一定的过毒效果 这篇文章来讲解如何通过手动注入来实现apk的捆绑 工具:mt管理器 首先我们要明白原理:木马的payload存在于其dex文件中,将木马的payload注入到正常apk中&…...
【YOLO 系列】基于YOLO的道路坑洞检测识别系统【python源码+Pyqt5界面+数据集+训练代码】
前言 在传统的道路维护和管理中,道路坑洞的检测通常依赖人工巡查,这种方式不仅效率低下,容易出现漏检和误检的情况,而且在复杂的路况和恶劣的天气条件下,检测人员的安全也难以保障。而基于 YOLO 的道路坑洞检测系统&a…...
以项目的方式学QT开发(一)——超详细讲解(120000多字详细讲解,涵盖qt大量知识)逐步更新!
以项目的方式学QT开发 以项目的方式学QT开发 P1 QT介绍 1.1 QT简介 1.2 QT安装 1.2.1 Windows QT安装 1.2.2 QT Creator 使用基本介绍 P2 C基础 2.1 命名空间 2.1.1 命名空间作用 2.1.2 自定义命名空间 2.2 从C语言快速入门 2.2.1 输入输出 2.2.2 基…...
大模型学习
ChatTempate,Completion Only,NEFTune,SFTTrainer 微调技术 (背景:预训练后的大模型只会根据上文,输出下文,但效果不好,要微调帮他更好理解) ChatTemplate 是一种用于定…...
print()函数详解:输出文字、变量与格式化
用ChatGPT做软件测试 “掌握输出,才能掌控信息;理解输出,才能洞悉程序运行的本质。” 当我们敲下人生第一个 Python 代码: print("Hello, World!")也许并未意识到,我们接触的是整个编程世界中最基础、却也最…...
RPC与SOAP的区别
一.RPC(远程过程调用)和SOAP(简单对象访问协议)均用于实现分布式系统中的远程通信,但两者在设计理念、协议实现及应用场景上存在显著差异。 二.对比 1.设计理念 2.协议规范 3.技术特性 4.典型应用场景 5.总结 三.总结…...
2025认证杯数学建模A题思路+代码+模型:小行星轨迹预测
2025认证杯数学建模A题思路代码模型,详细内容见文末名片 近地小行星( Near Earth Asteroids, NEAs )是轨道相对接近地球的小行 星,它的正式定义为椭圆轨道的近日距不大于 1.3 天文单位( AU )的小行星。 …...
Axure中继器高保真交互原型的核心元件
Axure作为一款强大的原型设计工具,中继器无疑是打造高保真交互原型的核心利器。今天,就让我们深入探讨一下Axure中继器的核心地位、操作难点,以及如何借助优秀案例来提升我们的中继器使用技能。 一、核心地位 中继器在Axure中的地位举足轻重…...
Java中Money类的使用及与BigDecimal的对比
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、为什么需要Money类? 在金融和商业计算中,精确的货币处理是至关重要的。虽然Java提供了BigDecimal类来处理高精度计算,…...
第三章:系统命令
1.系统当前时间 date命令: 2.切换用户 su 用户名 sudo 命令:表示使用超级管理员身份执行该命令,如果你当前不是管理员,希望以管理员身份执行某个命令时,使用sudo,需要输入超级管理员的密码: …...
第 83 场周赛:较大分组的位置、隐藏个人信息、连续整数求和、统计子串中的唯一字符
Q1、[简单] 较大分组的位置 1、题目描述 在一个由小写字母构成的字符串 s 中,包含由一些连续的相同字符所构成的分组。 例如,在字符串 s "abbxxxxzyy" 中,就含有 "a", "bb", "xxxx", "z&qu…...
NY244NY249美光闪存颗粒NY252NY256
NY244NY249美光闪存颗粒NY252NY256 美光闪存颗粒技术解析:从架构创新到性能突围 在数据中心轰鸣的服务器阵列中,某款新型存储颗粒正悄然改变着数据吞吐的规则。以NY系列为代表的美光闪存,凭借3D NAND架构与电荷捕获技术的深度融合ÿ…...
MCP本地高效与云端实时:stdio 与 HTTP+SSE 传输机制深度对比
概览 模型上下文协议(MCP)定义了客户端与服务器之间通信的统一标准,所有消息均采用 JSON-RPC 2.0 格式进行封装,并在此基础上支持两种传输机制:stdio(标准输入/输出) 与 HTTPSSE(Se…...
[IP地址科普] 服务器公网IP、私网IP、弹性IP是什么?区别与应用场景详解
更多服务器知识,尽在hostol.com 当我们谈论让一台服务器连接到互联网,或者让服务器上的网站、应用能够被用户访问时,IP 地址是绝对绕不开的核心概念。它就像是每台联网设备的唯一“身份证号码”和“邮政编码”,使得数据包能够在浩…...
【Python】在vscode利用pyinstaller中的.spec文件把py项目打包为.exe实现非py环境下使用的操作步骤
【需要打包的项目结构-简单】 【打包步骤】 【1-将图标以.ico的格式保存在项目中】 可以用.jpg或.png的图像进行重名,注意要和项目在同一个路径下 【2-创建并填写main.sepc文件】 在终端输入以下指令自动创建main.sepc文件,会自动生成标准的文件 pyi…...
MySQL如何查看某个表所占空间大小?(表空间大小查看方法)
文章目录 一、使用SQL查询查看表空间1.1 查询所有表的大小(包括数据和索引)1.2 查询特定数据库的表大小1.3 查询单个表的详细空间信息 二、使用命令行工具查看表空间2.1 使用mysql客户端查询2.2 查看物理文件大小(适用于MyISAM/InnoDB&#x…...
[数据结构]7. 堆-Heap
堆-Heap 1. 介绍2. 堆的实现3. 堆操作InitlilzeDestorySwapPushPopTopEmptySizeAdjustUpAdjustDown 4. HeapSort5. Top-K 1. 介绍 堆(heap) 是一种满足特定条件的完全二叉树。 小顶堆(min heap):任意节点的值 ≤ 其子…...
对心理幸福感含义的探索 | 幸福就是一切吗?
注:机翻,未校。 Happiness Is Everything, or Is It? Explorations on the Meaning of Psychological Well-Being 幸福就是一切吗?对心理幸福感含义的探索 Journal of Personality and Social Psychology 1989, Vol. 57, No. 6,1069-1081 …...
Java应用OOM排查:面试通关“三部曲”心法
开篇点题:OOM——Java应用的“内存爆仓”警报 OOM (OutOfMemoryError) 是啥病?想象一下,你的Java应用程序是一个大仓库,内存就是仓库的存储空间。如果货物(程序运行时创建的对象)越来越多,超出了…...
第28周——InceptionV1实现猴痘识别
前言 🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 一、前期准备 1.检查GPU import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision im…...
云上玩转 Qwen3 系列之三:PAI-LangStudio x Hologres构建ChatBI数据分析Agent应用
本文详细介绍了如何使用 LangStudio 和 Qwen3 构建基于 MCP 协议的 Hologres ChatBI 智能 Agent 应用。该应用通过将 Agent、MCP Server 等技术和阿里最新的推理模型 Qwen3 编排在一个应用流中,为大模型提供了 MCPOLAP 的智能数据分析能力,使用自然语言即…...
Android开发-在应用之间共享数据
在Android系统中,应用之间的隔离机制(沙箱机制)保障了系统的安全性与稳定性。然而,在实际开发中,我们经常需要实现跨应用的数据共享,例如: 从一个应用向另一个应用传递用户信息;多个…...
MySQL-数据库分布式XA事务
准备 innodb存储引擎开启支持分布式事务 set global innodb_support_axonMySQL数据库XA事务的SQL语法如下: XA {START| BEGIN} xid {JOIN | RESUME} XA END xid {SUSPEND [ FOR MIGRATE]} XA PREPARE xid XA COMMIT xid [ONE PHASE] XA ROLLBACK xid XA RECOVER 完…...
如何快速入门-衡石科技分析平台
快速指南 创建管理员账号 按照文档安装成功之后,假设安装所在服务器 IP 是<Server IP>,端口是<Server Port>,则可以通过浏览器访问http://<Server IP>:<Server Port>/ 访问衡石分析平台,如果正常&a…...
20250515通过以太网让VLC拉取视熙科技的机芯的rtsp视频流的步骤
20250515通过以太网让VLC拉取视熙科技的机芯的rtsp视频流的步骤 2025/5/15 20:26 缘起:荣品的PRO-RK3566适配视熙科技 的4800W的机芯。 1080p出图预览的时候没图了。 通过105的机芯出图确认 荣品的PRO-RK3566 的硬件正常。 然后要确认 视熙科技 的4800W的机芯是否出…...