1. 概述

简单来说,Apache Commons Collections 的 CollectionUtils 提供了一系列实用方法,用于处理常见的集合操作。这些方法覆盖了广泛的使用场景,能有效减少我们编写样板代码的工作量。该库主要面向较旧的 JVM 版本,因为 Java 8 的 Stream API 已经提供了类似功能。

2. Maven 依赖

要使用 CollectionUtils,我们需要添加以下 Maven 依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

最新版本可以在 这里 找到。

3. 环境准备

我们先定义两个基础类 CustomerAddress

public class Customer {
    private Integer id;
    private String name;
    private Address address;

    // 标准 getter 和 setter
}

public class Address {
    private String locality;
    private String city;
   
    // 标准 getter 和 setter
}

为了测试后续实现,我们准备以下 Customer 对象和 List 实例:

Customer customer1 = new Customer(1, "Daniel", "locality1", "city1");
Customer customer2 = new Customer(2, "Fredrik", "locality2", "city2");
Customer customer3 = new Customer(3, "Kyle", "locality3", "city3");
Customer customer4 = new Customer(4, "Bob", "locality4", "city4");
Customer customer5 = new Customer(5, "Cat", "locality5", "city5");
Customer customer6 = new Customer(6, "John", "locality6", "city6");

List<Customer> list1 = Arrays.asList(customer1, customer2, customer3);
List<Customer> list2 = Arrays.asList(customer4, customer5, customer6);
List<Customer> list3 = Arrays.asList(customer1, customer2);

List<Customer> linkedList1 = new LinkedList<>(list1);

4. CollectionUtils 核心方法

下面我们介绍 Apache Commons CollectionUtils 中最常用的几个方法。

4.1 添加非空元素

使用 addIgnoreNull 方法可以仅向集合中添加非空元素。该方法接收两个参数:

  • 目标集合
  • 待添加元素
@Test
public void givenList_whenAddIgnoreNull_thenNoNullAdded() {
    CollectionUtils.addIgnoreNull(list1, null);
 
    assertFalse(list1.contains(null));
}

✅ 注意:null 值不会被添加到列表中。

4.2 合并有序列表

使用 collate 方法可以合并两个已排序的列表。该方法返回一个新的有序列表:

@Test
public void givenTwoSortedLists_whenCollated_thenSorted() {
    List<Customer> sortedList = CollectionUtils.collate(list1, list2);

    assertEquals(6, sortedList.size()); 
    assertTrue(sortedList.get(0).getName().equals("Bob"));
    assertTrue(sortedList.get(2).getName().equals("Daniel"));
}

4.3 对象转换

通过 transform 方法可以将 A 类对象列表转换为 B 类对象列表。需要提供:

  • 原始对象列表
  • 转换器(Transformer)
@Test
public void givenListOfCustomers_whenTransformed_thenListOfAddress() {
    Collection<Address> addressCol = CollectionUtils.collect(list1, 
      new Transformer<Customer, Address>() {
        public Address transform(Customer customer) {
            return customer.getAddress();
        }
    });
    
    List<Address> addressList = new ArrayList<>(addressCol);
    assertTrue(addressList.size() == 3);
    assertTrue(addressList.get(0).getLocality().equals("locality1"));
}

4.4 对象过滤

使用 filter 方法可以移除列表中不满足条件的元素。参数包括:

  • 目标列表
  • 断言(Predicate)

⚠️ 注意:filterInverse 方法作用相反,会移除满足条件的元素。两个方法都返回 boolean 表示列表是否被修改:

@Test
public void givenCustomerList_WhenFiltered_thenCorrectSize() {
    
    boolean isModified = CollectionUtils.filter(linkedList1, 
      new Predicate<Customer>() {
        public boolean evaluate(Customer customer) {
            return Arrays.asList("Daniel","Kyle").contains(customer.getName());
        }
    });
     
    assertTrue(linkedListList1.size() == 2);
}

如果需要返回过滤后的新列表而非布尔值,可以使用 selectselectRejected

4.5 非空检查

isNotEmpty 方法是检查集合是否至少包含一个元素的利器。传统写法:

boolean isNotEmpty = (list != null && list.size() > 0);

使用 CollectionUtils.isNotEmpty 更简洁:

@Test
public void givenNonEmptyList_whenCheckedIsNotEmpty_thenTrue() {
    assertTrue(CollectionUtils.isNotEmpty(list1));
}

isEmpty 方法作用相反,检查集合是否为 null 或空:

List<Customer> emptyList = new ArrayList<>();
List<Customer> nullList = null;
 
assertTrue(CollectionUtils.isEmpty(nullList));
assertTrue(CollectionUtils.isEmpty(emptyList));

4.6 包含关系检查

使用 isSubCollection 可以检查一个集合是否是另一个集合的子集:

@Test
public void givenCustomerListAndASubcollection_whenChecked_thenTrue() {
    assertTrue(CollectionUtils.isSubCollection(list3, list1));
}

子集定义:集合 A 中每个元素的出现次数 ≤ 集合 B 中的出现次数。

4.7 集合交集

使用 intersection 方法获取两个集合的交集:

@Test
public void givenTwoLists_whenIntersected_thenCheckSize() {
    Collection<Customer> intersection = CollectionUtils.intersection(list1, list3);
    assertTrue(intersection.size() == 2);
}

结果中元素的出现次数 = 两个输入集合中该元素出现次数的最小值。

4.8 集合差集

使用 subtract 方法计算差集(存在于第一个集合但不存在于第二个集合的元素):

@Test
public void givenTwoLists_whenSubtracted_thenCheckElementNotPresentInA() {
    Collection<Customer> result = CollectionUtils.subtract(list1, list3);
    assertFalse(result.contains(customer1));
}

结果中元素的出现次数 = 第一个集合中的出现次数 - 第二个集合中的出现次数。

4.9 集合并集

使用 union 方法计算两个集合的并集:

@Test
public void givenTwoLists_whenUnioned_thenCheckElementPresentInResult() {
    Collection<Customer> union = CollectionUtils.union(list1, list2);
 
    assertTrue(union.contains(customer1));
    assertTrue(union.contains(customer4));
}

结果中元素的出现次数 = 两个输入集合中该元素出现次数的最大值。

5. 总结

到这里就结束了。我们介绍了 CollectionUtils 中最常用的几个方法,这些方法在 Java 项目中处理集合时能有效减少样板代码。完整代码可以在 GitHub 上查看。


原始标题:Apache Commons Collections CollectionUtils