Apache Commons CollectionUtils 工具类详解:方法介绍与实战应用
1. 概述
org.apache.commons.collections4.CollectionUtils 是 Apache Commons Collections 库中的一个核心工具类,专门用于简化 Java 集合(List、Set、Map 等)的常见操作。它提供了丰富的静态方法,涵盖了集合的空值判断、集合运算、过滤转换、比较统计等多种场景,能够显著减少冗余代码,提高开发效率和代码可读性。
在传统的 Java 开发中,我们经常需要编写重复的代码来处理集合,例如手动判断集合是否为空、使用循环实现集合的交集和并集操作等。这些代码不仅冗长,而且容易出错。CollectionUtils 工具类的出现,使得我们能够通过一行代码完成复杂的集合操作,让开发人员更专注于业务逻辑而非底层实现。
工具类优势总结:
- 代码简洁性:减少模板代码,使集合操作更直观。
- 安全性:内置空指针安全处理,避免常见的
NullPointerException。 - 功能丰富:提供集合运算、过滤、转换等一站式解决方案。
- 高性能:经过优化测试,保证操作效率。
2. 环境准备
在使用 CollectionUtils 工具类之前,我们需要在项目中引入 Apache Commons Collections4 库。
Maven 依赖配置
xml
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
Gradle 依赖配置
gradle
implementation 'org.apache.commons:commons-collections4:4.4'
注意:Commons Collections 有两个主要版本:commons-collections(旧版本 3.x,不支持泛型)和 commons-collections4(版本 4.x,支持泛型并需要 Java 8 以上)。推荐直接使用 commons-collections4 以获得更好的类型安全和功能支持。
3. 常用方法详解与实例
下面我们将 CollectionUtils 的常用方法分为几大类,分别介绍其功能并提供实际代码示例。
3.1 集合判空操作
空值判断是集合操作中最基础也是最常见的需求。CollectionUtils 提供了安全的方法来处理可能为空的集合。
| 方法名 | 功能描述 | 返回值 |
|---|---|---|
isEmpty(Collection<?> coll) |
判断集合为 null 或空 | boolean |
isNotEmpty(Collection<?> coll) |
判断集合非 null 且非空 | boolean |
emptyIfNull(Collection<T> coll) |
集合为 null 时返回空集合 | Collection |
传统判空方式 vs CollectionUtils:
java
// 传统方式:需要手动检查 null 和 empty
if (list == null || list.isEmpty()) {
// 处理空集合逻辑
}
// 使用 CollectionUtils:一行代码搞定
if (CollectionUtils.isEmpty(list)) {
// 处理空集合逻辑
}
完整示例代码:
java
import org.apache.commons.collections4.CollectionUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class EmptyCheckExample {
public static void main(String[] args) {
// 测试各种集合状态
List<String> nullList = null;
List<String> emptyList = new ArrayList<>();
List<String> normalList = Arrays.asList("A", "B", "C");
// isEmpty 方法测试
System.out.println("nullList isEmpty: " + CollectionUtils.isEmpty(nullList)); // true
System.out.println("emptyList isEmpty: " + CollectionUtils.isEmpty(emptyList)); // true
System.out.println("normalList isEmpty: " + CollectionUtils.isEmpty(normalList)); // false
// isNotEmpty 方法测试
System.out.println("nullList isNotEmpty: " + CollectionUtils.isNotEmpty(nullList)); // false
System.out.println("normalList isNotEmpty: " + CollectionUtils.isNotEmpty(normalList)); // true
// emptyIfNull 方法测试
List<String> safeList1 = CollectionUtils.emptyIfNull(nullList);
List<String> safeList2 = CollectionUtils.emptyIfNull(normalList);
System.out.println("safeList1 size: " + safeList1.size()); // 0
System.out.println("safeList2: " + safeList2); // [A, B, C]
}
}
运行结果:
nullList isEmpty: true
emptyList isEmpty: true
normalList isEmpty: false
nullList isNotEmpty: false
normalList isNotEmpty: true
safeList1 size: 0
safeList2: [A, B, C]
3.2 集合运算操作
CollectionUtils 提供了一系列数学集合运算方法,可以轻松实现交集、并集、差集等常见操作。
3.2.1 并集(Union)
并集操作返回两个集合中所有不重复的元素。
java
public class UnionExample {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A", "B", "C");
List<String> list2 = Arrays.asList("B", "C", "D");
Collection<String> union = CollectionUtils.union(list1, list2);
System.out.println("并集结果: " + union); // [A, B, C, D]
}
}
3.2.2 交集(Intersection)
交集操作返回两个集合中共有的元素。
java
public class IntersectionExample {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A", "B", "C");
List<String> list2 = Arrays.asList("B", "C", "D");
Collection<String> intersection = CollectionUtils.intersection(list1, list2);
System.out.println("交集结果: " + intersection); // [B, C]
}
}
3.2.3 差集(Subtract)
差集操作返回第一个集合中有而第二个集合中没有的元素。
java
public class SubtractExample {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A", "B", "C");
List<String> list2 = Arrays.asList("B", "C", "D");
Collection<String> subtract = CollectionUtils.subtract(list1, list2);
System.out.println("差集结果: " + subtract); // [A]
}
}
3.2.4 对称差集(Disjunction)
对称差集返回两个集合中互不相同的元素,即去掉交集后的所有元素。
java
public class DisjunctionExample {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A", "B", "C");
List<String> list2 = Arrays.asList("B", "C", "D");
Collection<String> disjunction = CollectionUtils.disjunction(list1, list2);
System.out.println("对称差集结果: " + disjunction); // [A, D]
}
}
3.3 集合过滤与转换
CollectionUtils 提供了强大的过滤和转换功能,可以轻松处理集合中的元素。
3.3.1 过滤(Filter)
filter 方法会直接修改原集合,只保留满足条件的元素。
java
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import java.util.Arrays;
import java.util.List;
public class FilterExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6));
// 过滤偶数:使用 Predicate 接口
CollectionUtils.filter(numbers, new Predicate<Integer>() {
@Override
public boolean evaluate(Integer number) {
return number % 2 == 0;
}
});
System.out.println("过滤后的集合: " + numbers); // [2, 4, 6]
// Java 8+ 可以使用 Lambda 表达式简化
List<Integer> anotherList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
CollectionUtils.filter(anotherList, n -> n % 2 == 0);
System.out.println("Lambda 过滤结果: " + anotherList); // [2, 4]
}
}
3.3.2 转换(Collect)
collect 方法将集合中的元素转换为另一种类型,返回新集合而不修改原集合。
java
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Transformer;
import java.util.Arrays;
import java.util.List;
public class CollectExample {
public static void main(String[] args) {
List<String> stringList = Arrays.asList("1", "2", "3", "4", "5");
// 将字符串转换为整数
List<Integer> integerList = (List<Integer>) CollectionUtils.collect(stringList, new Transformer<String, Integer>() {
@Override
public Integer transform(String input) {
return Integer.parseInt(input);
}
});
System.out.println("转换后的集合: " + integerList); // [1, 2, 3, 4, 5]
// 使用 Lambda 表达式简化
List<Integer> lambdaResult = (List<Integer>) CollectionUtils.collect(stringList, s -> Integer.parseInt(s));
System.out.println("Lambda 转换结果: " + lambdaResult); // [1, 2, 3, 4, 5]
}
}
3.3.3 属性提取实例
在实际开发中,我们经常需要从对象集合中提取某个属性的集合。
java
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Transformer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PropertyExtractionExample {
public static void main(String[] args) {
// 创建包含人员信息的Map列表
List<Map<String, Object>> personList = new ArrayList<>();
Map<String, Object> person1 = new HashMap<>();
person1.put("name", "张三");
person1.put("age", 25);
person1.put("department", "技术部");
Map<String, Object> person2 = new HashMap<>();
person2.put("name", "李四");
person2.put("age", 30);
person2.put("department", "市场部");
Map<String, Object> person3 = new HashMap<>();
person3.put("name", "王五");
person3.put("age", 28);
person3.put("department", "技术部");
personList.add(person1);
personList.add(person2);
personList.add(person3);
// 提取所有人员姓名
List<String> nameList = (List<String>) CollectionUtils.collect(personList, new Transformer<Map<String, Object>, String>() {
@Override
public String transform(Map<String, Object> person) {
return (String) person.get("name");
}
});
System.out.println("人员姓名列表: " + nameList); // [张三, 李四, 王五]
// 提取特定部门的人员
List<Map<String, Object>> techPersons = new ArrayList<>(personList);
CollectionUtils.filter(techPersons, new Predicate<Map<String, Object>>() {
@Override
public boolean evaluate(Map<String, Object> person) {
return "技术部".equals(person.get("department"));
}
});
System.out.println("技术部人员数量: " + techPersons.size()); // 2
}
}
3.4 集合比较与统计
CollectionUtils 提供了多种比较和统计方法,方便我们对集合数据进行验证和分析。
3.4.1 包含判断
java
import org.apache.commons.collections4.CollectionUtils;
import java.util.Arrays;
import java.util.List;
public class ContainsExample {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A", "B", "C", "D", "E");
List<String> list2 = Arrays.asList("B", "D");
List<String> list3 = Arrays.asList("X", "Y");
// 判断 list1 是否包含 list2 的所有元素
boolean containsAll = CollectionUtils.containsAll(list1, list2);
System.out.println("list1 包含 list2 所有元素: " + containsAll); // true
// 判断两个集合是否有任何共同元素
boolean containsAny = CollectionUtils.containsAny(list1, list2);
System.out.println("list1 和 list2 有共同元素: " + containsAny); // true
boolean containsAny2 = CollectionUtils.containsAny(list1, list3);
System.out.println("list1 和 list3 有共同元素: " + containsAny2); // false
}
}
3.4.2 集合相等判断
isEqualCollection 方法判断两个集合是否包含相同的元素(忽略顺序)。
java
public class EqualCollectionExample {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("A", "B", "C", "C"); // 有两个 C
List<String> list2 = Arrays.asList("C", "B", "A", "C"); // 顺序不同,但元素相同
List<String> list3 = Arrays.asList("A", "B", "C"); // 只有一个 C
boolean isEqual1 = CollectionUtils.isEqualCollection(list1, list2);
boolean isEqual2 = CollectionUtils.isEqualCollection(list1, list3);
System.out.println("list1 和 list2 是否相等: " + isEqual1); // true
System.out.println("list1 和 list3 是否相等: " + isEqual2); // false
}
}
3.4.3 元素统计
frequency 方法统计指定元素在集合中出现的次数。
java
public class FrequencyExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple", "banana", "apple", "orange", "apple", "banana");
int appleCount = CollectionUtils.frequency(fruits, "apple");
int bananaCount = CollectionUtils.frequency(fruits, "banana");
int orangeCount = CollectionUtils.frequency(fruits, "orange");
int grapeCount = CollectionUtils.frequency(fruits, "grape");
System.out.println("苹果出现次数: " + appleCount); // 3
System.out.println("香蕉出现次数: " + bananaCount); // 2
System.out.println("橙子出现次数: " + orangeCount); // 1
System.out.println("葡萄出现次数: " + grapeCount); // 0
}
}
3.5 其他实用方法
3.5.1 安全添加元素
addIgnoreNull 方法在添加元素时会忽略 null 值,避免集合中出现不必要的空值。
java
import org.apache.commons.collections4.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
public class AddIgnoreNullExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 安全添加元素
CollectionUtils.addIgnoreNull(list, "Hello");
CollectionUtils.addIgnoreNull(list, null); // 这个不会被添加
CollectionUtils.addIgnoreNull(list, "World");
System.out.println("列表内容: " + list); // [Hello, World]
}
}
3.5.2 合并有序集合
collate 方法用于合并两个已排序的集合,并保持排序顺序。
java
import org.apache.commons.collections4.CollectionUtils;
import java.util.Arrays;
import java.util.List;
public class CollateExample {
public static void main(String[] args) {
List<String> sortedList1 = Arrays.asList("A", "C", "E");
List<String> sortedList2 = Arrays.asList("B", "D", "F");
List<String> mergedList = CollectionUtils.collate(sortedList1, sortedList2);
System.out.println("合并后的有序列表: " + mergedList); // [A, B, C, D, E, F]
}
}
4. 实战应用案例
4.1 案例一:用户订单过滤系统
假设我们有一个电商系统,需要从用户订单中筛选出符合特定条件的高价值订单。
java
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
// 订单类
class Order {
private String orderId;
private String userId;
private double amount;
private String status;
public Order(String orderId, String userId, double amount, String status) {
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
this.status = status;
}
// getter 方法省略...
}
// 用户订单过滤系统
public class OrderFilterSystem {
public static void main(String[] args) {
// 模拟订单数据
List<Order> orders = Arrays.asList(
new Order("001", "user1", 1500.0, "completed"),
new Order("002", "user2", 800.0, "completed"),
new Order("003", "user3", 2500.0, "pending"),
new Order("004", "user1", 1200.0, "completed"),
new Order("005", "user4", 3000.0, "completed")
);
// 筛选已完成的高价值订单(金额大于1000)
List<Order> highValueOrders = new ArrayList<>(orders);
CollectionUtils.filter(highValueOrders, new Predicate<Order>() {
@Override
public boolean evaluate(Order order) {
return "completed".equals(order.getStatus()) && order.getAmount() > 1000;
}
});
System.out.println("高价值订单数量: " + highValueOrders.size());
// 提取订单金额
List<Double> amounts = (List<Double>) CollectionUtils.collect(highValueOrders, new Transformer<Order, Double>() {
@Override
public Double transform(Order order) {
return order.getAmount();
}
});
System.out.println("高价值订单金额: " + amounts);
// 计算总金额
double totalAmount = 0;
for (Double amount : amounts) {
totalAmount += amount;
}
System.out.println("高价值订单总金额: " + totalAmount);
}
}
4.2 案例二:数据分析与报表生成
在企业级应用中,我们经常需要对数据进行各种分析处理。
java
import org.apache.commons.collections4.CollectionUtils;
import java.util.*;
public class DataAnalysisExample {
public static void main(String[] args) {
// 模拟销售数据
List<Map<String, Object>> salesData = Arrays.asList(
createRecord("2024-01", "北京", "产品A", 100),
createRecord("2024-01", "上海", "产品A", 150),
createRecord("2024-01", "北京", "产品B", 200),
createRecord("2024-02", "北京", "产品A", 120),
createRecord("2024-02", "上海", "产品B", 180)
);
// 1. 找出所有不同的产品
Set<String> allProducts = new HashSet<>();
CollectionUtils.collect(salesData, record -> (String) record.get("product"), allProducts);
System.out.println("所有产品: " + allProducts);
// 2. 筛选北京地区的销售记录
List<Map<String, Object>> beijingSales = new ArrayList<>(salesData);
CollectionUtils.filter(beijingSales, record -> "北京".equals(record.get("region")));
System.out.println("北京地区销售记录数量: " + beijingSales.size());
// 3. 按月份分组统计
Map<String, Integer> monthlySales = new HashMap<>();
for (Map<String, Object> record : salesData) {
String month = (String) record.get("month");
Integer amount = (Integer) record.get("amount");
monthlySales.put(month, monthlySales.getOrDefault(month, 0) + amount);
}
System.out.println("月度销售统计: " + monthlySales);
// 4. 找出销量最好的产品
Map<String, Integer> productSales = new HashMap<>();
for (Map<String, Object> record : salesData) {
String product = (String) record.get("product");
Integer amount = (Integer) record.get("amount");
productSales.put(product, productSales.getOrDefault(product, 0) + amount);
}
String bestProduct = Collections.max(productSales.entrySet(), Map.Entry.comparingByValue()).getKey();
System.out.println("销量最好的产品: " + bestProduct + ", 销量: " + productSales.get(bestProduct));
}
private static Map<String, Object> createRecord(String month, String region, String product, int amount) {
Map<String, Object> record = new HashMap<>();
record.put("month", month);
record.put("region", region);
record.put("product", product);
record.put("amount", amount);
return record;
}
}
5. 总结与最佳实践
Apache Commons CollectionUtils 是一个功能强大且实用的工具类,它可以显著简化集合操作代码,提高开发效率。通过本文的介绍,我们可以看到它在各种场景下的强大应用能力。
5.1 主要优势总结
- 代码简洁性:将复杂的集合操作简化为单行方法调用,减少样板代码。
- 空安全:内置对 null 值的处理,避免空指针异常。
- 功能全面:提供集合运算、过滤、转换、统计等一站式解决方案。
- 性能优化:经过充分测试和优化,保证执行效率。
5.2 最佳实践建议
-
版本选择:优先选择
commons-collections4而不是旧版的commons-collections,以获得更好的泛型支持和性能。 -
与 Java Stream API 的配合使用:在 Java 8+ 环境中,可以结合使用 CollectionUtils 和 Stream API,根据具体场景选择更合适的工具。
java// CollectionUtils 方式 CollectionUtils.filter(list, predicate); // Stream API 方式 list.stream().filter(predicate).collect(Collectors.toList()); -
性能注意事项:
- 对于大型集合,注意集合运算方法(如
union,intersection)会创建新集合,可能带来内存开销。 - 在频繁操作的场景下,考虑使用原生循环或 Stream API 进行性能优化。
- 对于大型集合,注意集合运算方法(如
-
集合选择策略:
- 需要有序且不重复:
SetUniqueList - 需要计数功能:
Bag实现类 - 需要双向映射:
BidiMap
- 需要有序且不重复:
5.3 学习建议
对于初学者来说,建议从最常用的方法开始掌握:
- 先熟练掌握空值判断方法(
isEmpty,isNotEmpty) - 然后学习集合运算方法(
union,intersection,subtract) - 最后掌握过滤转换等高级功能(
filter,collect)
随着实践的深入,可以进一步探索 Collections 框架中的其他工具类,如 ListUtils, SetUtils, MapUtils 等,它们为特定类型的集合提供了更专业的操作方法。
CollectionUtils 工具类是 Java 开发者工具箱中不可或缺的利器,合理使用它将使你的代码更加简洁、健壮和可维护。