跳到主要内容

Java 集合工具类详解

1. 集合工具类概述

Java 提供了丰富的集合工具类,主要包括 CollectionsArrays 工具类,以及 Apache Commons Collections 等第三方库。这些工具类提供了大量便捷的方法来操作集合,大大简化了集合操作的复杂度。

核心价值

集合工具类 = 便捷操作 + 性能优化 + 线程安全 + 代码复用

  • 🛠️ 便捷操作 - 提供丰富的方法简化常见集合操作,如排序、查找、转换等
  • 性能优化 - 经过优化的算法实现,提供高效的集合处理能力
  • 🔒 线程安全 - 提供线程安全的集合包装和操作方法,简化并发编程
  • 📦 代码复用 - 减少重复代码,提高开发效率和代码质量
  • 🧩 标准化 - 提供统一的API接口,使代码更加一致和可维护

1.1 什么是集合工具类?

集合工具类是一组静态方法的集合,专门用于操作 Java 集合框架中的各种集合类型。它们提供了排序、查找、同步、不可变集合创建等常用功能,让开发者能够更高效地处理集合数据。

主要工具类分类

工具类主要功能适用场景
Collections集合操作、排序、查找、同步List、Set、Map 等集合类型
Arrays数组操作、排序、查找、转换各种数组类型
Apache Commons扩展功能、集合操作复杂业务场景
Stream API函数式操作、并行处理数据流处理

1.2 工具类设计原则

工具类设计原则示例
java
1public class CollectionUtilsDesign {
2
3 // 1. 静态方法设计
4 public static <T> boolean isEmpty(Collection<T> collection) {
5 return collection == null || collection.isEmpty();
6 }
7
8 // 2. 泛型支持
9 public static <T> List<T> filter(Collection<T> collection, Predicate<T> predicate) {
10 return collection.stream()
11 .filter(predicate)
12 .collect(Collectors.toList());
13 }
14
15 // 3. 空值安全
16 public static <T> int safeSize(Collection<T> collection) {
17 return collection == null ? 0 : collection.size();
18 }
19
20 // 4. 不可变集合
21 public static <T> List<T> immutableList(Collection<T> collection) {
22 return Collections.unmodifiableList(new ArrayList<>(collection));
23 }
24}
设计特点
  • 静态方法:无需实例化,直接调用
  • 泛型支持:类型安全,编译时检查
  • 空值安全:避免空指针异常
  • 不可变性:提供不可变集合,保证数据安全

2. Collections 工具类详解

Collections 工具类是 Java 集合框架中最重要的工具类,提供了丰富的静态方法来操作各种集合类型。

2.1 排序操作

Collections 工具类提供了多种排序方法,支持自然排序和自定义排序:

基本排序操作示例
java
1public class CollectionsSortExample {
2 public static void main(String[] args) {
3 // 自然排序(要求元素实现Comparable接口)
4 List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
5 Collections.sort(names);
6 System.out.println("自然排序后: " + names);
7 // 输出: [Alice, Bob, Charlie, David]
8
9 // 自定义排序(使用Comparator)
10 List<Person> people = Arrays.asList(
11 new Person("Alice", 25),
12 new Person("Bob", 30),
13 new Person("Charlie", 20),
14 new Person("David", 28)
15 );
16
17 // 按年龄排序
18 Collections.sort(people, Comparator.comparing(Person::getAge));
19 System.out.println("按年龄排序: " + people);
20
21 // 按姓名排序
22 Collections.sort(people, Comparator.comparing(Person::getName));
23 System.out.println("按姓名排序: " + people);
24
25 // 逆序排序
26 Collections.sort(names, Collections.reverseOrder());
27 System.out.println("逆序排序: " + names);
28 // 输出: [David, Charlie, Bob, Alice]
29 }
30
31 static class Person {
32 private String name;
33 private int age;
34
35 public Person(String name, int age) {
36 this.name = name;
37 this.age = age;
38 }
39
40 public String getName() { return name; }
41 public int getAge() { return age; }
42
43 @Override
44 public String toString() {
45 return name + "(" + age + ")";
46 }
47 }
48}

排序方法对比

方法说明时间复杂度适用场景
Collections.sort(List)自然排序O(n log n)元素已实现Comparable
Collections.sort(List, Comparator)自定义排序O(n log n)需要自定义排序逻辑
Collections.reverseOrder()逆序比较器-需要逆序排序
Collections.shuffle(List)随机打乱O(n)需要随机顺序

2.2 查找和替换操作

Collections 工具类提供了高效的查找和替换方法,特别是二分查找算法:

查找和替换操作示例
java
1public class CollectionsSearchExample {
2 public static void main(String[] args) {
3 // 二分查找(要求列表已排序)
4 List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15);
5 System.out.println("有序列表: " + numbers);
6
7 int target = 7;
8 int index = Collections.binarySearch(numbers, target);
9 if (index >= 0) {
10 System.out.println(target + " 的索引: " + index);
11 } else {
12 System.out.println(target + " 未找到,应插入位置: " + (-index - 1));
13 }
14
15 // 查找最大最小值
16 Integer max = Collections.max(numbers);
17 Integer min = Collections.min(numbers);
18 System.out.println("最大值: " + max + ", 最小值: " + min);
19
20 // 替换所有元素
21 List<String> list = new ArrayList<>(Arrays.asList("a", "b", "a", "c", "a"));
22 System.out.println("替换前: " + list);
23 Collections.replaceAll(list, "a", "x");
24 System.out.println("替换后: " + list);
25
26 // 填充集合
27 List<String> fillList = new ArrayList<>(Arrays.asList("a", "b", "c"));
28 System.out.println("填充前: " + fillList);
29 Collections.fill(fillList, "default");
30 System.out.println("填充后: " + fillList);
31
32 // 查找子列表位置
33 List<String> source = Arrays.asList("a", "b", "c", "d", "e", "f");
34 List<String> target1 = Arrays.asList("c", "d");
35 List<String> target2 = Arrays.asList("x", "y");
36
37 int firstIndex = Collections.indexOfSubList(source, target1);
38 int lastIndex = Collections.lastIndexOfSubList(source, target1);
39 System.out.println("子列表 " + target1 + " 首次出现位置: " + firstIndex);
40 System.out.println("子列表 " + target1 + " 最后出现位置: " + lastIndex);
41
42 int notFound = Collections.indexOfSubList(source, target2);
43 System.out.println("子列表 " + target2 + " 位置: " + notFound);
44 }
45}

查找方法性能对比

方法时间复杂度前提条件适用场景
Collections.binarySearch()O(log n)列表已排序有序列表快速查找
Collections.max()/min()O(n)查找最大最小值
Collections.indexOfSubList()O(n*m)查找子列表位置
Collections.frequency()O(n)统计元素出现次数

3. Arrays 工具类详解

Arrays 工具类是 Java 中专门用于操作数组的工具类,提供了排序、查找、比较、填充等常用功能。

3.1 数组排序和查找

Arrays 工具类提供了高效的数组排序和查找方法:

数组排序和查找示例
java
1public class ArraysSortExample {
2 public static void main(String[] args) {
3 // 基本类型数组排序
4 int[] numbers = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
5 System.out.println("原始数组: " + Arrays.toString(numbers));
6
7 // 完整排序
8 Arrays.sort(numbers);
9 System.out.println("排序后: " + Arrays.toString(numbers));
10
11 // 部分排序(只排序索引2到7的元素)
12 int[] partialSort = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
13 System.out.println("部分排序前: " + Arrays.toString(partialSort));
14 Arrays.sort(partialSort, 2, 8);
15 System.out.println("部分排序后: " + Arrays.toString(partialSort));
16
17 // 二分查找(要求数组已排序)
18 int target = 5;
19 int index = Arrays.binarySearch(numbers, target);
20 if (index >= 0) {
21 System.out.println(target + " 的索引: " + index);
22 } else {
23 System.out.println(target + " 未找到,应插入位置: " + (-index - 1));
24 }
25
26 // 查找所有匹配的元素
27 List<Integer> indices = new ArrayList<>();
28 for (int i = 0; i < numbers.length; i++) {
29 if (numbers[i] == target) {
30 indices.add(i);
31 }
32 }
33 System.out.println(target + " 的所有索引: " + indices);
34
35 // 对象数组排序
36 String[] names = {"Charlie", "Alice", "Bob", "David", "Eve"};
37 System.out.println("原始字符串数组: " + Arrays.toString(names));
38
39 // 自然排序
40 Arrays.sort(names);
41 System.out.println("自然排序后: " + Arrays.toString(names));
42
43 // 自定义排序(按长度)
44 Arrays.sort(names, Comparator.comparing(String::length));
45 System.out.println("按长度排序后: " + Arrays.toString(names));
46
47 // 并行排序(大数据量)
48 int[] largeArray = new int[100000];
49 Random random = new Random(42);
50 for (int i = 0; i < largeArray.length; i++) {
51 largeArray[i] = random.nextInt(10000);
52 }
53
54 long startTime = System.currentTimeMillis();
55 Arrays.sort(largeArray);
56 long endTime = System.currentTimeMillis();
57 System.out.println("普通排序耗时: " + (endTime - startTime) + "ms");
58
59 // 重置数组
60 for (int i = 0; i < largeArray.length; i++) {
61 largeArray[i] = random.nextInt(10000);
62 }
63
64 startTime = System.currentTimeMillis();
65 Arrays.parallelSort(largeArray);
66 endTime = System.currentTimeMillis();
67 System.out.println("并行排序耗时: " + (endTime - startTime) + "ms");
68 }
69}

排序方法性能对比

方法适用类型时间复杂度适用场景
Arrays.sort()基本类型、对象数组O(n log n)一般排序需求
Arrays.parallelSort()基本类型、对象数组O(n log n)大数据量排序
Arrays.sort(array, from, to)基本类型、对象数组O(n log n)部分排序
Arrays.sort(array, comparator)对象数组O(n log n)自定义排序

3.2 数组比较和填充

Arrays 工具类提供了数组比较和填充的便捷方法:

数组比较和填充示例
java
1public class ArraysComparisonExample {
2 public static void main(String[] args) {
3 // 一维数组比较
4 int[] arr1 = {1, 2, 3, 4, 5};
5 int[] arr2 = {1, 2, 3, 4, 5};
6 int[] arr3 = {1, 2, 3, 4, 6};
7
8 System.out.println("arr1: " + Arrays.toString(arr1));
9 System.out.println("arr2: " + Arrays.toString(arr2));
10 System.out.println("arr3: " + Arrays.toString(arr3));
11
12 boolean equals1 = Arrays.equals(arr1, arr2);
13 boolean equals2 = Arrays.equals(arr1, arr3);
14
15 System.out.println("arr1 equals arr2: " + equals1);
16 System.out.println("arr1 equals arr3: " + equals2);
17
18 // 多维数组深度比较
19 int[][] matrix1 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
20 int[][] matrix2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
21 int[][] matrix3 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 0}};
22
23 System.out.println("matrix1: " + Arrays.deepToString(matrix1));
24 System.out.println("matrix2: " + Arrays.deepToString(matrix2));
25 System.out.println("matrix3: " + Arrays.deepToString(matrix3));
26
27 boolean deepEquals1 = Arrays.deepEquals(matrix1, matrix2);
28 boolean deepEquals2 = Arrays.deepEquals(matrix1, matrix3);
29
30 System.out.println("matrix1 deepEquals matrix2: " + deepEquals1);
31 System.out.println("matrix1 deepEquals matrix3: " + deepEquals2);
32
33 // 数组填充
34 int[] fillArray = new int[8];
35 System.out.println("填充前: " + Arrays.toString(fillArray));
36
37 // 全部填充
38 Arrays.fill(fillArray, 42);
39 System.out.println("全部填充42后: " + Arrays.toString(fillArray));
40
41 // 部分填充
42 Arrays.fill(fillArray, 2, 6, 100);
43 System.out.println("索引2-5填充100后: " + Arrays.toString(fillArray));
44
45 // 重置数组
46 Arrays.fill(fillArray, 0);
47 System.out.println("重置为0后: " + Arrays.toString(fillArray));
48
49 // 对象数组填充
50 String[] stringArray = new String[5];
51 System.out.println("字符串数组填充前: " + Arrays.toString(stringArray));
52
53 Arrays.fill(stringArray, "default");
54 System.out.println("填充default后: " + Arrays.toString(stringArray));
55
56 // 部分填充字符串
57 Arrays.fill(stringArray, 1, 4, "custom");
58 System.out.println("索引1-3填充custom后: " + Arrays.toString(stringArray));
59
60 // 数组复制和比较
61 int[] original = {1, 2, 3, 4, 5};
62 int[] copy1 = Arrays.copyOf(original, 3); // 复制前3个元素
63 int[] copy2 = Arrays.copyOf(original, 7); // 复制并扩展长度
64 int[] copy3 = Arrays.copyOfRange(original, 1, 4); // 复制指定范围
65
66 System.out.println("原始数组: " + Arrays.toString(original));
67 System.out.println("复制前3个: " + Arrays.toString(copy1));
68 System.out.println("复制并扩展: " + Arrays.toString(copy2));
69 System.out.println("复制范围1-3: " + Arrays.toString(copy3));
70
71 // 比较不同长度的数组
72 boolean equalsLength = Arrays.equals(original, copy1);
73 System.out.println("original equals copy1: " + equalsLength);
74 }
75}

比较和填充方法对比

方法功能适用场景注意事项
Arrays.equals()一维数组比较简单数组比较只比较引用和内容,不比较长度
Arrays.deepEquals()多维数组比较嵌套数组比较递归比较所有层级
Arrays.fill()数组填充初始化或重置数组支持部分填充
Arrays.copyOf()数组复制创建数组副本可以改变数组长度

3.3 数组转换

Arrays 工具类提供了丰富的数组转换方法,支持数组与集合、流之间的转换:

数组转换示例
java
1public class ArraysConversionExample {
2 public static void main(String[] args) {
3 // 基本类型数组转List
4 int[] intArray = {1, 2, 3, 4, 5};
5 System.out.println("原始int数组: " + Arrays.toString(intArray));
6
7 // 基本类型数组转Stream
8 IntStream intStream = Arrays.stream(intArray);
9 List<Integer> intList = intStream.boxed().collect(Collectors.toList());
10 System.out.println("转换为List: " + intList);
11
12 // 对象数组转List
13 String[] stringArray = {"Alice", "Bob", "Charlie", "David"};
14 System.out.println("原始字符串数组: " + Arrays.toString(stringArray));
15
16 // 使用Arrays.asList转换
17 List<String> stringList = Arrays.asList(stringArray);
18 System.out.println("Arrays.asList结果: " + stringList);
19
20 // 注意:Arrays.asList返回的List是固定大小的
21 try {
22 stringList.add("Eve"); // 抛出UnsupportedOperationException
23 } catch (UnsupportedOperationException e) {
24 System.out.println("不能修改固定大小的List: " + e.getMessage());
25 }
26
27 // 创建可修改的List
28 List<String> modifiableList = new ArrayList<>(Arrays.asList(stringArray));
29 modifiableList.add("Eve");
30 System.out.println("可修改的List: " + modifiableList);
31
32 // 使用Stream API转换
33 List<String> streamList = Arrays.stream(stringArray)
34 .filter(s -> s.length() > 4)
35 .map(String::toUpperCase)
36 .collect(Collectors.toList());
37 System.out.println("Stream转换结果: " + streamList);
38
39 // 多维数组转换
40 int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
41 System.out.println("原始矩阵: " + Arrays.deepToString(matrix));
42
43 // 多维数组转Stream
44 List<Integer> flatList = Arrays.stream(matrix)
45 .flatMapToInt(Arrays::stream)
46 .boxed()
47 .collect(Collectors.toList());
48 System.out.println("展平后的List: " + flatList);
49
50 // 数组转Set(去重)
51 int[] duplicateArray = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
52 Set<Integer> uniqueSet = Arrays.stream(duplicateArray)
53 .boxed()
54 .collect(Collectors.toSet());
55 System.out.println("去重后的Set: " + uniqueSet);
56
57 // 数组转Map
58 String[] keys = {"name", "age", "city"};
59 Object[] values = {"Alice", 25, "New York"};
60
61 Map<String, Object> map = new HashMap<>();
62 for (int i = 0; i < keys.length; i++) {
63 map.put(keys[i], values[i]);
64 }
65 System.out.println("转换后的Map: " + map);
66
67 // 使用Stream API创建Map
68 Map<String, Object> streamMap = IntStream.range(0, keys.length)
69 .boxed()
70 .collect(Collectors.toMap(
71 i -> keys[i],
72 i -> values[i]
73 ));
74 System.out.println("Stream创建的Map: " + streamMap);
75 }
76}

转换方法对比

方法功能返回值类型注意事项
Arrays.asList()数组转List固定大小List不能添加/删除元素
Arrays.stream()数组转StreamStream支持函数式操作
new ArrayList<>(Arrays.asList())数组转可变List可变List可以修改
Arrays.stream().boxed()基本类型转包装类型Stream<包装类型>自动装箱

4. 实用工具方法

在实际开发中,我们经常需要创建一些通用的工具方法来简化集合操作。以下是一些常用的实用工具方法:

4.1 集合判空和null检查

集合判空和null检查工具类
java
1public class CollectionUtils {
2
3 /**
4 * 检查集合是否为空
5 * @param collection 要检查的集合
6 * @return true如果集合为null或空,否则false
7 */
8 public static boolean isEmpty(Collection<?> collection) {
9 return collection == null || collection.isEmpty();
10 }
11
12 /**
13 * 检查集合是否不为空
14 * @param collection 要检查的集合
15 * @return true如果集合不为null且不为空,否则false
16 */
17 public static boolean isNotEmpty(Collection<?> collection) {
18 return !isEmpty(collection);
19 }
20
21 /**
22 * 安全获取集合大小
23 * @param collection 要检查的集合
24 * @return 集合大小,如果为null则返回0
25 */
26 public static int size(Collection<?> collection) {
27 return collection == null ? 0 : collection.size();
28 }
29
30 /**
31 * 检查Map是否为空
32 * @param map 要检查的Map
33 * @return true如果Map为null或空,否则false
34 */
35 public static boolean isEmpty(Map<?, ?> map) {
36 return map == null || map.isEmpty();
37 }
38
39 /**
40 * 检查Map是否不为空
41 * @param map 要检查的Map
42 * @return true如果Map不为null且不为空,否则false
43 */
44 public static boolean isNotEmpty(Map<?, ?> map) {
45 return !isEmpty(map);
46 }
47
48 /**
49 * 创建空集合
50 * @return 不可变的空List
51 */
52 public static <T> List<T> emptyList() {
53 return Collections.emptyList();
54 }
55
56 /**
57 * 创建空Set
58 * @return 不可变的空Set
59 */
60 public static <T> Set<T> emptySet() {
61 return Collections.emptySet();
62 }
63
64 /**
65 * 创建空Map
66 * @return 不可变的空Map
67 */
68 public static <K, V> Map<K, V> emptyMap() {
69 return Collections.emptyMap();
70 }
71
72 /**
73 * 检查数组是否为空
74 * @param array 要检查的数组
75 * @return true如果数组为null或长度为0,否则false
76 */
77 public static boolean isEmpty(Object[] array) {
78 return array == null || array.length == 0;
79 }
80
81 /**
82 * 检查数组是否不为空
83 * @param array 要检查的数组
84 * @return true如果数组不为null且长度大于0,否则false
85 */
86 public static boolean isNotEmpty(Object[] array) {
87 return !isEmpty(array);
88 }
89}

判空方法对比

方法功能返回值适用场景
isEmpty()检查集合/Map/数组是否为空boolean需要判断集合状态
isNotEmpty()检查集合/Map/数组是否不为空boolean需要判断集合状态
size()安全获取集合大小int需要获取集合大小
emptyXXX()创建空集合不可变集合作为默认返回值

4.2 集合转换工具

集合转换工具类提供了各种集合类型之间的转换方法:

集合转换工具类
java
1public class CollectionConverter {
2
3 /**
4 * List转Set(去重)
5 * @param list 要转换的List
6 * @return 包含List元素的Set
7 */
8 public static <T> Set<T> listToSet(List<T> list) {
9 if (isEmpty(list)) {
10 return new HashSet<>();
11 }
12 return new HashSet<>(list);
13 }
14
15 /**
16 * Set转List
17 * @param set 要转换的Set
18 * @return 包含Set元素的List
19 */
20 public static <T> List<T> setToList(Set<T> set) {
21 if (isEmpty(set)) {
22 return new ArrayList<>();
23 }
24 return new ArrayList<>(set);
25 }
26
27 /**
28 * 数组转List
29 * @param array 要转换的数组
30 * @return 包含数组元素的List
31 */
32 public static <T> List<T> arrayToList(T[] array) {
33 if (isEmpty(array)) {
34 return new ArrayList<>();
35 }
36 return Arrays.asList(array);
37 }
38
39 /**
40 * 数组转可变List
41 * @param array 要转换的数组
42 * @return 可修改的List
43 */
44 public static <T> List<T> arrayToModifiableList(T[] array) {
45 if (isEmpty(array)) {
46 return new ArrayList<>();
47 }
48 return new ArrayList<>(Arrays.asList(array));
49 }
50
51 /**
52 * List转数组
53 * @param list 要转换的List
54 * @param clazz 目标数组的类型
55 * @return 包含List元素的数组
56 */
57 public static <T> T[] listToArray(List<T> list, Class<T> clazz) {
58 if (isEmpty(list)) {
59 @SuppressWarnings("unchecked")
60 T[] array = (T[]) Array.newInstance(clazz, 0);
61 return array;
62 }
63
64 @SuppressWarnings("unchecked")
65 T[] array = (T[]) Array.newInstance(clazz, list.size());
66 return list.toArray(array);
67 }
68
69 /**
70 * 基本类型数组转包装类型List
71 * @param array 基本类型数组
72 * @return 包装类型List
73 */
74 public static List<Integer> intArrayToList(int[] array) {
75 if (array == null || array.length == 0) {
76 return new ArrayList<>();
77 }
78 return Arrays.stream(array).boxed().collect(Collectors.toList());
79 }
80
81 /**
82 * 基本类型数组转包装类型Set
83 * @param array 基本类型数组
84 * @return 包装类型Set
85 */
86 public static Set<Integer> intArrayToSet(int[] array) {
87 if (array == null || array.length == 0) {
88 return new HashSet<>();
89 }
90 return Arrays.stream(array).boxed().collect(Collectors.toSet());
91 }
92
93 /**
94 * 字符串数组转List
95 * @param array 字符串数组
96 * @return 字符串List
97 */
98 public static List<String> stringArrayToList(String[] array) {
99 if (isEmpty(array)) {
100 return new ArrayList<>();
101 }
102 return Arrays.asList(array);
103 }
104
105 /**
106 * 字符串数组转Set(去重)
107 * @param array 字符串数组
108 * @return 字符串Set
109 */
110 public static Set<String> stringArrayToSet(String[] array) {
111 if (isEmpty(array)) {
112 return new HashSet<>();
113 }
114 return new HashSet<>(Arrays.asList(array));
115 }
116
117 /**
118 * 集合转字符串
119 * @param collection 要转换的集合
120 * @param delimiter 分隔符
121 * @return 用分隔符连接的字符串
122 */
123 public static String collectionToString(Collection<?> collection, String delimiter) {
124 if (isEmpty(collection)) {
125 return "";
126 }
127 return collection.stream()
128 .map(Object::toString)
129 .collect(Collectors.joining(delimiter));
130 }
131
132 /**
133 * 字符串转List
134 * @param str 要转换的字符串
135 * @param delimiter 分隔符
136 * @return 分割后的字符串List
137 */
138 public static List<String> stringToList(String str, String delimiter) {
139 if (str == null || str.trim().isEmpty()) {
140 return new ArrayList<>();
141 }
142 return Arrays.asList(str.split(delimiter));
143 }
144}

转换方法功能对比

方法功能输入类型输出类型特点
listToSet()List转SetList<T>Set<T>自动去重
setToList()Set转ListSet<T>List<T>保持顺序
arrayToList()数组转ListT[]List<T>固定大小
arrayToModifiableList()数组转可变ListT[]List<T>可修改
listToArray()List转数组List<T>T[]类型安全

4.3 集合操作工具

集合操作工具类提供了集合之间的数学运算,如交集、并集、差集等:

集合操作工具类
java
1public class CollectionOperations {
2
3 /**
4 * 计算两个集合的交集
5 * @param c1 第一个集合
6 * @param c2 第二个集合
7 * @return 包含共同元素的Set
8 */
9 public static <T> Set<T> intersection(Collection<T> c1, Collection<T> c2) {
10 if (isEmpty(c1) || isEmpty(c2)) {
11 return new HashSet<>();
12 }
13 Set<T> result = new HashSet<>(c1);
14 result.retainAll(c2);
15 return result;
16 }
17
18 /**
19 * 计算两个集合的并集
20 * @param c1 第一个集合
21 * @param c2 第二个集合
22 * @return 包含所有元素的Set
23 */
24 public static <T> Set<T> union(Collection<T> c1, Collection<T> c2) {
25 Set<T> result = new HashSet<>();
26 if (isNotEmpty(c1)) {
27 result.addAll(c1);
28 }
29 if (isNotEmpty(c2)) {
30 result.addAll(c2);
31 }
32 return result;
33 }
34
35 /**
36 * 计算两个集合的差集(c1 - c2)
37 * @param c1 第一个集合
38 * @param c2 第二个集合
39 * @return 包含c1中但不在c2中的元素
40 */
41 public static <T> Set<T> difference(Collection<T> c1, Collection<T> c2) {
42 if (isEmpty(c1)) {
43 return new HashSet<>();
44 }
45 if (isEmpty(c2)) {
46 return new HashSet<>(c1);
47 }
48 Set<T> result = new HashSet<>(c1);
49 result.removeAll(c2);
50 return result;
51 }
52
53 /**
54 * 计算两个集合的对称差集(并集 - 交集)
55 * @param c1 第一个集合
56 * @param c2 第二个集合
57 * @return 包含只在一个集合中出现的元素
58 */
59 public static <T> Set<T> symmetricDifference(Collection<T> c1, Collection<T> c2) {
60 Set<T> union = union(c1, c2);
61 Set<T> intersection = intersection(c1, c2);
62 union.removeAll(intersection);
63 return union;
64 }
65
66 /**
67 * 分割集合为指定大小的子集合
68 * @param list 要分割的List
69 * @param size 每个子集合的大小
70 * @return 分割后的子集合List
71 */
72 public static <T> List<List<T>> partition(List<T> list, int size) {
73 if (isEmpty(list) || size <= 0) {
74 return new ArrayList<>();
75 }
76
77 List<List<T>> partitions = new ArrayList<>();
78 for (int i = 0; i < list.size(); i += size) {
79 int end = Math.min(i + size, list.size());
80 partitions.add(list.subList(i, end));
81 }
82 return partitions;
83 }
84
85 /**
86 * 检查一个集合是否是另一个集合的子集
87 * @param subset 可能的子集
88 * @param superset 可能的超集
89 * @return true如果subset是superset的子集
90 */
91 public static <T> boolean isSubset(Collection<T> subset, Collection<T> superset) {
92 if (isEmpty(subset)) {
93 return true; // 空集合是任何集合的子集
94 }
95 if (isEmpty(superset)) {
96 return false;
97 }
98 return superset.containsAll(subset);
99 }
100
101 /**
102 * 检查两个集合是否相等(忽略顺序)
103 * @param c1 第一个集合
104 * @param c2 第二个集合
105 * @return true如果两个集合包含相同的元素
106 */
107 public static <T> boolean equalsIgnoreOrder(Collection<T> c1, Collection<T> c2) {
108 if (c1 == c2) {
109 return true;
110 }
111 if (isEmpty(c1) && isEmpty(c2)) {
112 return true;
113 }
114 if (isEmpty(c1) || isEmpty(c2)) {
115 return false;
116 }
117 if (c1.size() != c2.size()) {
118 return false;
119 }
120
121 // 使用Map统计元素出现次数
122 Map<T, Integer> countMap = new HashMap<>();
123 for (T element : c1) {
124 countMap.merge(element, 1, Integer::sum);
125 }
126
127 for (T element : c2) {
128 Integer count = countMap.get(element);
129 if (count == null || count == 0) {
130 return false;
131 }
132 countMap.put(element, count - 1);
133 }
134
135 return true;
136 }
137
138 /**
139 * 找出集合中的重复元素
140 * @param collection 要检查的集合
141 * @return 包含重复元素的Set
142 */
143 public static <T> Set<T> findDuplicates(Collection<T> collection) {
144 if (isEmpty(collection)) {
145 return new HashSet<>();
146 }
147
148 Set<T> seen = new HashSet<>();
149 Set<T> duplicates = new HashSet<>();
150
151 for (T element : collection) {
152 if (!seen.add(element)) {
153 duplicates.add(element);
154 }
155 }
156
157 return duplicates;
158 }
159
160 /**
161 * 随机选择集合中的元素
162 * @param collection 要选择的集合
163 * @param count 要选择的元素数量
164 * @return 随机选择的元素List
165 */
166 public static <T> List<T> randomSample(Collection<T> collection, int count) {
167 if (isEmpty(collection) || count <= 0) {
168 return new ArrayList<>();
169 }
170
171 List<T> list = new ArrayList<>(collection);
172 if (count >= list.size()) {
173 return list;
174 }
175
176 List<T> result = new ArrayList<>();
177 Random random = new Random();
178
179 for (int i = 0; i < count; i++) {
180 int index = random.nextInt(list.size());
181 result.add(list.get(index));
182 list.remove(index);
183 }
184
185 return result;
186 }
187}

集合操作方法对比

方法功能时间复杂度适用场景
intersection()计算交集O(n+m)找出共同元素
union()计算并集O(n+m)合并两个集合
difference()计算差集O(n+m)找出独有元素
symmetricDifference()计算对称差集O(n+m)找出不同元素
partition()分割集合O(n)分批处理数据
findDuplicates()找出重复元素O(n)找出重复数据
1## 5. 实际应用场景
2
3### 5.1 数据处理和分析
4
5```java title="数据处理和分析示例"
6public class DataProcessingExample {
7 public static void main(String[] args) {
8 // 用户数据统计
9 List<User> users = Arrays.asList(
10 new User("Alice", 25, "Engineer"),
11 new User("Bob", 30, "Manager"),
12 new User("Charlie", 25, "Engineer"),
13 new User("David", 35, "Director"),
14 new User("Eve", 28, "Engineer")
15 );
16
17 // 使用Collections工具类进行数据分析
18 System.out.println("=== 用户数据分析 ===");
19
20 // 按年龄分组统计
21 Map<Integer, Long> ageDistribution = users.stream()
22 .collect(Collectors.groupingBy(User::getAge, Collectors.counting()));
23 System.out.println("年龄分布: " + ageDistribution);
24
25 // 找出重复的职业
26 List<String> jobs = users.stream().map(User::getJob).collect(Collectors.toList());
27 Set<String> duplicateJobs = CollectionOperations.findDuplicates(jobs);
28 System.out.println("重复职业: " + duplicateJobs);
29
30 // 按职业分组,找出每个职业的平均年龄
31 Map<String, Double> avgAgeByJob = users.stream()
32 .collect(Collectors.groupingBy(
33 User::getJob,
34 Collectors.averagingInt(User::getAge)
35 ));
36 System.out.println("各职业平均年龄: " + avgAgeByJob);
37
38 // 找出年龄最大的用户
39 User oldestUser = Collections.max(users, Comparator.comparing(User::getAge));
40 System.out.println("年龄最大的用户: " + oldestUser);
41
42 // 按年龄排序
43 List<User> sortedByAge = new ArrayList<>(users);
44 Collections.sort(sortedByAge, Comparator.comparing(User::getAge));
45 System.out.println("按年龄排序: " + sortedByAge);
46 }
47}
48
49class User {
50 private String name;
51 private int age;
52 private String job;
53
54 // 构造函数、getter、setter省略...
55}

5.2 缓存和配置管理

缓存和配置管理示例
java
1public class CacheConfigExample {
2 private static final Map<String, Object> configCache = Collections.synchronizedMap(new HashMap<>());
3 private static final Set<String> blacklist = Collections.newSetFromMap(new ConcurrentHashMap<>());
4
5 public static void main(String[] args) {
6 // 配置缓存管理
7 System.out.println("=== 配置缓存管理 ===");
8
9 // 安全地添加配置
10 safePutConfig("database.url", "jdbc:mysql://localhost:3306/test");
11 safePutConfig("cache.ttl", 3600);
12 safePutConfig("max.connections", 100);
13
14 // 批量获取配置
15 List<String> keys = Arrays.asList("database.url", "cache.ttl", "max.connections");
16 Map<String, Object> configs = getConfigs(keys);
17 System.out.println("获取的配置: " + configs);
18
19 // 黑名单管理
20 addToBlacklist("spam@example.com");
21 addToBlacklist("malware@example.com");
22 addToBlacklist("phishing@example.com");
23
24 System.out.println("黑名单大小: " + blacklist.size());
25 System.out.println("是否在黑名单中: " + isBlacklisted("spam@example.com"));
26
27 // 配置验证
28 validateConfigs(configs);
29 }
30
31 private static void safePutConfig(String key, Object value) {
32 if (CollectionUtils.isNotEmpty(key) && value != null) {
33 configCache.put(key, value);
34 }
35 }
36
37 private static Map<String, Object> getConfigs(List<String> keys) {
38 if (CollectionUtils.isEmpty(keys)) {
39 return Collections.emptyMap();
40 }
41
42 return keys.stream()
43 .filter(configCache::containsKey)
44 .collect(Collectors.toMap(key -> key, configCache::get));
45 }
46
47 private static void addToBlacklist(String email) {
48 if (CollectionUtils.isNotEmpty(email)) {
49 blacklist.add(email);
50 }
51 }
52
53 private static boolean isBlacklisted(String email) {
54 return CollectionUtils.isNotEmpty(email) && blacklist.contains(email);
55 }
56
57 private static void validateConfigs(Map<String, Object> configs) {
58 if (CollectionUtils.isEmpty(configs)) {
59 System.out.println("配置为空,跳过验证");
60 return;
61 }
62
63 // 验证必需的配置项
64 Set<String> requiredKeys = new HashSet<>(Arrays.asList("database.url", "max.connections"));
65 Set<String> missingKeys = CollectionOperations.difference(requiredKeys, configs.keySet());
66
67 if (CollectionUtils.isNotEmpty(missingKeys)) {
68 System.out.println("缺少必需配置: " + missingKeys);
69 } else {
70 System.out.println("所有必需配置都已存在");
71 }
72 }
73}

5.3 批量数据处理

批量数据处理示例
java
1public class BatchProcessingExample {
2 public static void main(String[] args) {
3 // 模拟大量数据
4 List<String> largeDataset = generateLargeDataset(10000);
5 System.out.println("=== 批量数据处理 ===");
6 System.out.println("数据集大小: " + largeDataset.size());
7
8 // 分批处理数据
9 int batchSize = 1000;
10 List<List<String>> batches = CollectionOperations.partition(largeDataset, batchSize);
11 System.out.println("分成 " + batches.size() + " 个批次");
12
13 // 并行处理每个批次
14 List<String> processedResults = batches.parallelStream()
15 .map(batch -> processBatch(batch))
16 .flatMap(List::stream)
17 .collect(Collectors.toList());
18
19 System.out.println("处理完成,结果数量: " + processedResults.size());
20
21 // 数据去重和统计
22 Set<String> uniqueResults = new HashSet<>(processedResults);
23 System.out.println("去重后结果数量: " + uniqueResults.size());
24
25 // 找出重复的数据
26 Set<String> duplicates = CollectionOperations.findDuplicates(processedResults);
27 System.out.println("重复数据数量: " + duplicates.size());
28
29 // 随机采样验证
30 List<String> sample = CollectionOperations.randomSample(uniqueResults, 10);
31 System.out.println("随机采样结果: " + sample);
32 }
33
34 private static List<String> generateLargeDataset(int size) {
35 List<String> dataset = new ArrayList<>();
36 Random random = new Random();
37
38 for (int i = 0; i < size; i++) {
39 dataset.add("data_" + random.nextInt(1000));
40 }
41
42 return dataset;
43 }
44
45 private static List<String> processBatch(List<String> batch) {
46 // 模拟批处理逻辑
47 return batch.stream()
48 .map(data -> "processed_" + data)
49 .collect(Collectors.toList());
50 }
51}

6. 最佳实践总结

6.1 工具类设计原则

核心价值

集合工具类的设计遵循以下原则:

  • 单一职责:每个方法只做一件事
  • 空安全:所有方法都要处理null和空集合
  • 性能优化:选择合适的算法和数据结构
  • 易用性:提供直观的API接口

6.2 性能优化策略

优化策略具体方法适用场景
预分配容量使用 new ArrayList<>(expectedSize)已知集合大小
选择合适的集合HashSet用于查找,TreeSet用于排序根据使用场景选择
并行处理使用 parallelStream()大数据量处理
避免装箱拆箱使用基本类型数组和Stream数值计算
缓存结果缓存频繁计算的结果重复计算

6.3 常见陷阱和解决方案

注意事项

在使用集合工具类时,需要注意以下常见陷阱:

  1. Arrays.asList()的不可变性

    java
    1// 错误用法
    2List<String> list = Arrays.asList("a", "b", "c");
    3list.add("d"); // 抛出UnsupportedOperationException
    4
    5// 正确用法
    6List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
    7list.add("d"); // 正常工作
  2. Collections.synchronizedXXX()的局限性

    java
    1// 注意:单个操作是线程安全的,但复合操作不是
    2List<String> syncList = Collections.synchronizedList(new ArrayList<>());
    3
    4// 错误:复合操作不是线程安全的
    5if (!syncList.contains("item")) {
    6 syncList.add("item"); // 可能重复添加
    7}
    8
    9// 正确:使用同步块
    10synchronized(syncList) {
    11 if (!syncList.contains("item")) {
    12 syncList.add("item");
    13 }
    14}
  3. Stream API的延迟执行

    java
    1// 注意:Stream是延迟执行的
    2Stream<String> stream = list.stream().filter(s -> s.length() > 5);
    3list.add("newItem"); // 这会影响stream的结果
    4
    5// 正确:先收集结果
    6List<String> result = list.stream().filter(s -> s.length() > 5).collect(Collectors.toList());
    7list.add("newItem"); // 不会影响已收集的结果

6.4 测试和调试建议

  1. 单元测试覆盖

    • 测试边界条件(空集合、null值)
    • 测试异常情况
    • 测试性能关键路径
  2. 调试技巧

    • 使用 Arrays.toString()Arrays.deepToString() 打印数组
    • 使用 Collections.toString() 打印集合
    • 使用Stream API的 peek() 方法调试流操作
  3. 性能监控

    • 监控集合操作的时间复杂度
    • 使用JMH进行性能基准测试
    • 监控内存使用情况

7. 总结

Java集合工具类为集合操作提供了强大而便捷的功能。通过合理使用Collections和Arrays工具类,我们可以:

  • 提高开发效率:避免重复编写集合操作代码
  • 保证代码质量:使用经过充分测试的标准库方法
  • 优化性能:选择合适的算法和数据结构
  • 增强可维护性:统一的API风格和错误处理

在实际开发中,我们应该:

  1. 优先使用标准库:Collections和Arrays工具类已经覆盖了大部分常见需求
  2. 合理封装:对于特定业务场景,可以基于标准工具类进行二次封装
  3. 注意性能:了解各种操作的时间复杂度,选择合适的实现
  4. 保持一致性:在项目中统一使用相同的工具类和方法

通过深入理解和熟练运用这些工具类,我们能够编写出更加高效、健壮和易维护的Java代码。

评论