Apache Commons Collections4 的详细指南

1. 什么是 Apache Commons Collections4?

Apache Commons Collections4 是一个强大的库,扩展了 Java 标准集合框架,提供了更复杂的集合操作。对于一年左右经验的 Java 开发者,它能帮助你更方便地处理双向映射、自动排序、过滤等功能,这些在标准集合类中很难实现。

2. 如何引入 Apache Commons Collections4?

通过 Maven 引入依赖:

xml 复制代码
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

3. 主要功能介绍

3.1. 双向 Map (BidiMap)

BidiMap 是 Apache Commons Collections 中提供的一种双向映射结构,允许你不仅可以通过 key 查找 value,还可以通过 value 查找 key。相比于 Java 标准库中的 HashMap,它提供了双向查找的能力,非常适合用于需要频繁进行 key-value 对称操作的场景。常见的实现包括:

  • DualHashBidiMap :使用 HashMap 实现的双向 Map,适合大多数通用场景,查找性能优异。
  • DualLinkedHashBidiMap :基于 LinkedHashMap 的实现,维护插入顺序的双向映射。
  • TreeBidiMap :基于 TreeMap,支持按自然顺序或自定义比较器排序的双向映射。

常见用法

3.1.1 插入和查找操作
BidiMap 的基础操作和普通的 Map 类似,但可以通过 getKey() 方法进行反向查找。

java 复制代码
BidiMap<String, String> bidiMap = new DualHashBidiMap<>();
bidiMap.put("a", "1");
bidiMap.put("b", "2");

System.out.println(bidiMap.get("a"));  // 输出 "1"
System.out.println(bidiMap.getKey("2"));  // 输出 "b"

3.1.2 删除操作

BidiMap 中,删除元素时会同时删除对应的 key 和 value。

java 复制代码
bidiMap.removeValue("1");  // 同时移除 key "a" 和 value "1"

实现对比

  • DualHashBidiMap:不保证顺序,但性能优越,适合大多数需要高效查找和插入的场景。
  • DualLinkedHashBidiMap:维护插入顺序,适合对顺序有要求的场景,如日志或展示数据。
  • TreeBidiMap:适用于需要排序的场景,如按字母顺序展示数据或构建有序索引。

应用场景

  • 编码与解码:在某些需要双向转换的场景中非常有用,如字母与摩尔斯电码的双向映射。
  • 数据库主键和业务键映射:你可能需要一个映射关系,同时能够通过主键查找业务键,反之亦然。
  • 缓存:可以用于缓存系统中快速查找值和反向查找。

3.2. 有序 Map 和 Set

Apache Commons Collections4 提供了一些额外的有序 MapSet 实现,它们扩展了 Java 原生集合类型的功能,特别是在排序和双向映射等方面。以下是它们的详细说明:

3.2.1 有序 Map

3.2.1.1 双向排序 Map
  • DualTreeBidiMap :这是一个基于 TreeMap 实现的双向 Map,它不仅允许根据键来排序,还可以根据值来排序。DualTreeBidiMap 保证了键和值的唯一性,并且提供了快速的键值对反转操作。

    用法示例

    java 复制代码
    BidiMap<String, Integer> bidiMap = new DualTreeBidiMap<>();
    bidiMap.put("apple", 1);
    bidiMap.put("banana", 2);
    bidiMap.put("cherry", 3);
    
    System.out.println(bidiMap);          // {apple=1, banana=2, cherry=3}
    System.out.println(bidiMap.inverseBidiMap());  // {1=apple, 2=banana, 3=cherry}

    主要特性

    • 按键和值的自然顺序进行排序。
    • 可以通过 inverseBidiMap() 获取反向映射。
3.2.1.2 按插入顺序的双向 Map
  • LinkedMap :这是一个在 Apache Commons Collections4 中的有序 Map,类似于 LinkedHashMap,它维护了插入顺序。与 LinkedHashMap 不同的是,LinkedMap 具有额外的遍历功能和方法,如 getFirstKey()getLastKey(),可以快速获取第一个和最后一个键。

    用法示例

java 复制代码
 Map<String, Integer> linkedMap = new LinkedMap<>();
 linkedMap.put("one", 1);
 linkedMap.put("two", 2);
 linkedMap.put("three", 3);
 
 System.out.println(linkedMap);  // {one=1, two=2, three=3}
 System.out.println(linkedMap.getFirstKey());  // one
 System.out.println(linkedMap.getLastKey());   // three

主要特性

  • 维护插入顺序。
  • 提供 getFirstKey()getLastKey() 等便捷方法
3.2.1.3 MultiKeyMap
  • MultiKeyMap<K, V>:这个类允许将多个键组合起来映射到一个值上。它对多个键的顺序也进行了维护,类似于 Map<K, List<V>> 的更高效实现,特别适用于组合键需要有序的情况。

    用法示例

    java 复制代码
    MultiKeyMap<String, Integer> multiKeyMap = new MultiKeyMap<>();
    multiKeyMap.put("apple", "red", 1);
    multiKeyMap.put("banana", "yellow", 2);
    
    System.out.println(multiKeyMap.get("apple", "red"));  // 1
    System.out.println(multiKeyMap.get("banana", "yellow"));  // 2

3.2.1.4 有序 Map 的应用场景

Apache Commons Collections4 提供的有序 Map 更适合以下场景:

  • 复杂的双向排序映射DualTreeBidiMap 适用于需要双向映射的场景,并且能够同时保持键和值的自然顺序。
  • 需要快速获取首尾元素的场景LinkedMap 提供了快速获取第一个和最后一个元素的能力,适合 FIFO、LRU 缓存等应用场景。
  • 多键组合场景MultiKeyMap 对多个键的管理和有序性进行扩展,适合多字段联合索引的情况。

3.2.2 有序 Set

3.2.2.1 双向排序 Set
  • TreeSortedSet :基于 TreeSet 的扩展,TreeSortedSet 维护元素的自然顺序或者自定义顺序,提供与 SortedSet 类似的操作。同时,它能够与双向 BidiMap 配合使用,以保证键和值的顺序统一。

    用法示例

    java 复制代码
    SortedSet<String> sortedSet = new TreeSortedSet<>();
    sortedSet.add("apple");
    sortedSet.add("banana");
    sortedSet.add("cherry");
    
    System.out.println(sortedSet);  // [apple, banana, cherry]
3.2.2.2 按插入顺序的 Set
  • ListOrderedSet :这是一个维护元素插入顺序的 Set,它是 SetList 的组合,内部通过 ArrayList 来维护顺序。适用于希望保持元素唯一且按插入顺序迭代的场景。

    用法示例

    java 复制代码
    Set<String> orderedSet = new ListOrderedSet<>(new HashSet<>());
    orderedSet.add("one");
    orderedSet.add("two");
    orderedSet.add("three");
    
    System.out.println(orderedSet);  // [one, two, three]

3.2.2.3 有序 Set 的应用场景

  • 按顺序操作的数据集合TreeSortedSet 适合需要根据自然顺序排序的集合操作。
  • 有序唯一元素集合ListOrderedSet 适用于插入顺序很重要并且需要保证元素唯一性的场景。

3.2.3 有序 Map 和 Set 的对比

特性 DualTreeBidiMap LinkedMap MultiKeyMap TreeSortedSet ListOrderedSet
顺序类型 键和值的自然顺序 插入顺序 多键的插入顺序 元素的自然顺序 插入顺序
底层数据结构 红黑树 HashMap + 双向链表 Map 组合 红黑树 ArrayList + Set
适用场景 双向映射与排序 需要获取首尾元素的场景 需要多键组合映射的场景 需要排序的集合操作 插入顺序的唯一集合操作
时间复杂度 O(log n) 查找、插入 O(1) 查找、插入 O(1) 查找、插入 O(log n) 查找、插入 O(1) 查找、插入

3.3. Bag

Bag 是 Apache Commons Collections4 提供的一种特殊集合,它允许在集合中存储相同元素的多个实例,并记录每个元素的出现次数。Bag 是对 Java 标准集合的一种扩展,适合用于处理多重集合或计数集合。Commons Collections4 中的 Bag 提供了多种实现,并有不同的优化特性。

3.3.1 Bag 接口

Bag 接口继承自 Collection,提供了额外的方法来处理元素的计数。与 Set 不同,Bag 允许存储相同元素的多个实例,但与 List 不同,Bag 关注的是元素的频率而非顺序。常用的方法包括:

  • add(E object, int n):添加 n 个给定的对象。
  • getCount(Object object):获取给定对象的出现次数。
  • remove(Object object, int n):删除指定数量的对象实例。

3.3.2 Bag 实现

Commons Collections4 提供了几种不同的 Bag 实现,针对不同的使用场景和性能需求:

3.3.2.1 HashBag

HashBag 基于 HashMap 实现,提供了高效的插入、删除和计数操作。它是一个无序的 Bag,适合不关心元素顺序的场景。HashBag 是最常用的 Bag 实现,具有较高的性能。

用法示例

java 复制代码
Bag<String> bag = new HashBag<>();
bag.add("apple", 3);   // 添加 3 个 "apple"
bag.add("banana", 2);  // 添加 2 个 "banana"
System.out.println(bag.getCount("apple"));  // 输出 3
System.out.println(bag);  // 输出 [apple, apple, apple, banana, banana]
3.3.2.2 TreeBag

TreeBagBag 的有序实现,基于 TreeMap,它确保元素按自然顺序或提供的比较器顺序进行存储。适合需要排序并统计元素出现次数的场景。

用法示例

java 复制代码
Bag<String> treeBag = new TreeBag<>();
treeBag.add("cherry", 2);
treeBag.add("apple", 3);
System.out.println(treeBag);  // 输出 [apple, apple, apple, cherry, cherry]

主要特性

  • 元素自动排序(自然顺序或自定义顺序)。
  • 时间复杂度为 O(log n)。
3.3.2.3 SynchronizedBag

SynchronizedBag 是线程安全的 Bag 实现,它通过对底层 Bag 进行包装,提供同步操作。适合多线程并发访问的场景。

用法示例

java 复制代码
Bag<String> syncBag = SynchronizedBag.synchronizedBag(new HashBag<>());
syncBag.add("apple", 1);
3.3.2.4 PredicatedBag

PredicatedBag 是一个带有过滤条件的 Bag,它确保只有满足特定条件的元素才能被添加到 Bag 中。适合需要约束集合元素的场景。

用法示例

java 复制代码
Predicate<String> noNull = Objects::nonNull;
Bag<String> predicatedBag = PredicatedBag.predicatedBag(new HashBag<>(), noNull);
predicatedBag.add("apple");  // 成功
predicatedBag.add(null);     // 抛出 IllegalArgumentException
3.3.2.5 TransformedBag

TransformedBag 是一个带有转换功能的 Bag,它会在元素添加到集合之前对其进行转换操作。适合需要在集合中存储规范化数据的场景。

用法示例

java 复制代码
Bag<String> transformedBag = TransformedBag.transformingBag(new HashBag<>(), String::toLowerCase);
transformedBag.add("APPLE");
System.out.println(transformedBag);  // 输出 [apple]

3.3.3 Bag 应用场景

Bag 的主要应用场景包括:

  • 元素计数 :当需要统计元素在集合中的出现次数时,Bag 是比 Map<E, Integer> 更合适的选择。
  • 多重集合操作:适合需要存储同一元素的多个实例的场景。
  • 频率分析:可以用于对数据进行频率分析,如词频统计、事件计数等。

3.3.4 Bag 实现对比

特性 HashBag TreeBag SynchronizedBag PredicatedBag TransformedBag
是否有序 是(自然顺序) 否(与底层 Bag 一致) 否(与底层 Bag 一致) 否(与底层 Bag 一致)
线程安全性
自定义元素约束
元素转换功能
底层数据结构 HashMap TreeMap 取决于包装的 Bag 实现 取决于包装的 Bag 实现 取决于包装的 Bag 实现
时间复杂度(增删查) O(1) O(log n) O(1) 或 O(log n) O(1) 或 O(log n) O(1) 或 O(log n)

3.3.5 Bag 的局限性

虽然 Bag 提供了对多重集合的高效支持,但它并不适用于所有场景。需要注意的是:

  • 顺序问题 :默认情况下,Bag 并不维护元素的插入顺序,如果需要顺序性,可以选择 TreeBag 或自行管理顺序。
  • 线程安全性 :大多数 Bag 实现并非线程安全,除非显式使用 SynchronizedBag

3.4. IteratorUtils

IteratorUtils 是 Apache Commons Collections4 提供的一个实用工具类,包含了一组静态方法,用于简化和增强 Java 的 Iterator 操作。它提供了多种便捷方法,帮助开发者处理迭代器的创建、组合、过滤和转换等功能。

3.4.1 主要方法

以下是 IteratorUtils 中的一些常用方法:

3.4.1.1 toList(Iterator<? extends T> iterator)

将给定的迭代器转换为 List。这对于将迭代器的数据转换为更常用的集合类型非常有用。

用法示例

java 复制代码
Iterator<String> iterator = Arrays.asList("apple", "banana", "cherry").iterator();
List<String> list = IteratorUtils.toList(iterator);
3.4.1.2 toArray(Iterator<? extends T> iterator)

将迭代器转换为数组。此方法适用于需要将迭代器的内容存储在数组中的场景。

用法示例

java 复制代码
Iterator<Integer> iterator = Arrays.asList(1, 2, 3).iterator();
Integer[] array = IteratorUtils.toArray(iterator);
3.4.1.3 emptyIterator()

返回一个空的迭代器。这在需要返回一个空集合的场景中非常有用。

用法示例

java 复制代码
Iterator<String> emptyIterator = IteratorUtils.emptyIterator();
3.4.1.4 asIterator(Enumeration<? extends T> enumeration)

Enumeration 转换为 Iterator。此方法在需要将旧版 API 与新 API 进行整合时非常实用。

用法示例

java 复制代码
Enumeration<String> enumeration = Collections.enumeration(Arrays.asList("one", "two", "three"));
Iterator<String> iterator = IteratorUtils.asIterator(enumeration);
3.4.1.5 filteredIterator(Iterator<? extends T> iterator, Predicate<? super T> predicate)

返回一个过滤后的迭代器,仅包含满足给定条件的元素。这对于在迭代过程中应用过滤条件非常有用。

用法示例

java 复制代码
Iterator<Integer> iterator = Arrays.asList(1, 2, 3, 4).iterator();
Iterator<Integer> filtered = IteratorUtils.filteredIterator(iterator, n -> n % 2 == 0); // 仅保留偶数
3.4.1.6 concatenatedIterator(Iterator<? extends T>... iterators)

将多个迭代器连接成一个迭代器,便于遍历多个集合中的元素。

用法示例

java 复制代码
Iterator<String> iterator1 = Arrays.asList("A", "B").iterator();
Iterator<String> iterator2 = Arrays.asList("C", "D").iterator();
Iterator<String> concatenated = IteratorUtils.concatenatedIterator(iterator1, iterator2);

3.4.2 应用场景

  • 集合转换:将迭代器内容转换为其他集合类型,简化数据处理。
  • 数据过滤:通过过滤条件,精确控制迭代器的输出。
  • 迭代器组合:在需要遍历多个集合时,方便地将多个迭代器合并。

3.4.3 IteratorUtils 优势

  • 简化代码:减少迭代器处理的样板代码,提高可读性。
  • 功能扩展:提供标准 Java 集合库没有的功能,如过滤和合并迭代器。
  • 兼容性 :支持将 Enumeration 转换为 Iterator,方便与旧版代码集成。

3.4.4 注意事项

  • 不支持并发IteratorUtils 的方法未提供对迭代器的并发安全支持,需在单线程环境中使用。
  • 懒惰求值:一些方法可能返回一个懒惰求值的迭代器,需注意迭代顺序和数据一致性。

3.5. Transformation 和 Predicate

TransformationPredicate 是 Apache Commons Collections4 中的重要接口,用于实现数据的转换和过滤逻辑。这些接口为处理集合和流提供了灵活的方式,特别是在需要对数据进行处理时。

3.5.1 Transformation

Transformation 接口用于定义一种从输入类型转换为输出类型的操作。它主要用于将集合中的元素进行转换,生成新的集合。

5.1.1 主要方法
  • transform(Object input):接收输入对象,并返回转换后的对象。

用法示例

java 复制代码
Transformation<String, Integer> transformation = new Transformation<String, Integer>() {
    @Override
    public Integer transform(String input) {
        return input.length(); // 转换为字符串的长度
    }
};
5.1.2 使用场景
  • 集合转换:将一个集合中的对象转换为另一种类型的集合。
  • 数据处理:对集合中的每个元素应用转换逻辑,生成新的数据视图。
5.1.3 例子

使用 CollectionUtils 类中的 collect 方法,将一个字符串集合转换为其长度集合:

java 复制代码
List<String> strings = Arrays.asList("one", "two", "three");
List<Integer> lengths = (List<Integer>) CollectionUtils.collect(strings, transformation);

3.5.2 Predicate

Predicate 接口用于定义一种条件测试操作,判断给定对象是否满足特定条件。它主要用于过滤集合中的元素。

5.2.1 主要方法
  • evaluate(Object object):接收对象并返回布尔值,表示对象是否满足条件。

用法示例

java 复制代码
Predicate<String> predicate = new Predicate<String>() {
    @Override
    public boolean evaluate(String input) {
        return input.length() > 3; // 判断字符串长度是否大于3
    }
};
5.2.2 使用场景
  • 集合过滤:从集合中筛选出符合条件的元素。
  • 条件逻辑:在复杂逻辑中使用,可嵌套组合多个条件。
5.2.3 例子

使用 CollectionUtils 类中的 select 方法,过滤出长度大于3的字符串:

java 复制代码
List<String> strings = Arrays.asList("one", "two", "three", "four");
List<String> filtered = (List<String>) CollectionUtils.select(strings, predicate);

3.5.3 组合使用

TransformationPredicate 可以结合使用,首先通过 Predicate 过滤集合,然后使用 Transformation 进行转换。例如,先筛选出符合条件的元素,再将它们转换为另一种类型。

java 复制代码
List<String> strings = Arrays.asList("one", "two", "three", "four");
Predicate<String> predicate = input -> input.length() > 3;
Transformation<String, Integer> transformation = String::length;

List<Integer> lengths = (List<Integer>) CollectionUtils.collect(
    (List<String>) CollectionUtils.select(strings, predicate),
    transformation
);

4. 其他实用工具

4.1. CollectionUtils

CollectionUtils 是 Apache Commons Collections4 中的一个工具类,专门用于提供一系列集合操作的静态方法。这些方法简化了常见的集合处理任务,帮助开发者更高效地管理集合。

4.1.1 主要功能

  • 空值检查 :验证集合是否为空或为 null,避免在操作集合时引发 NullPointerException
  • 集合操作:提供对集合的批量添加、合并、过滤和转换等功能。
  • 集合比较:支持集合之间的比较,包括交集、并集、差集等操作。
  • 集合分割:将一个集合拆分为多个小集合。

4.1.2 常用方法

  • isEmpty(Collection coll) :检查集合是否为空或为 null。如果集合为 null 或没有元素,则返回 true

    java 复制代码
    boolean isEmpty = CollectionUtils.isEmpty(myList);
  • addAll(Collection<? super T> coll, T... elements):将指定的元素数组添加到集合中。此方法是一个便捷的方式来批量添加元素。

    java 复制代码
    CollectionUtils.addAll(myList, "one", "two", "three");
  • select(Collection collection, Predicate<? super E> predicate) :返回符合条件的元素集合。Predicate 用于定义筛选条件。

    java 复制代码
    List<String> filtered = (List<String>) CollectionUtils.select(myList, s -> s.length() > 3);
  • collect(Collection collection, Transformation<? super E, ? extends T> transformation):将集合中的元素通过指定的转换逻辑进行转换,返回新的集合。

    java 复制代码
    List<Integer> lengths = (List<Integer>) CollectionUtils.collect(myList, String::length);
  • union(Collection<?> collection1, Collection<?> collection2):返回两个集合的并集,结果包含两个集合中的所有元素。

    java 复制代码
    Collection<?> union = CollectionUtils.union(collection1, collection2);
  • intersection(Collection<?> collection1, Collection<?> collection2):返回两个集合的交集,结果只包含两个集合中都存在的元素。

    java 复制代码
    Collection<?> intersection = CollectionUtils.intersection(collection1, collection2);
  • subtract(Collection<?> collection1, Collection<?> collection2):返回在第一个集合中存在但不在第二个集合中的元素。

    java 复制代码
    Collection<?> difference = CollectionUtils.subtract(collection1, collection2);
  • partition(Collection collection, Predicate<? super E> predicate):根据给定条件将集合分割成两个子集合。

    java 复制代码
    Map<Boolean, List<String>> partitioned = CollectionUtils.partition(myList, s -> s.length() > 3);

4.1.3 使用场景

  • 空集合处理 :在执行操作前,使用 isEmpty 方法检查集合的状态,防止空指针异常。
  • 集合批量操作 :使用 addAll 快速添加多个元素,简化代码。
  • 数据筛选 :通过 select 方法对集合进行条件筛选,获取满足特定条件的元素。
  • 数据转换 :利用 collect 方法将集合元素转换为其他类型,便于后续操作。
  • 集合运算 :通过 unionintersectionsubtract 方法进行集合的基本运算。
  • 集合分割:在处理复杂数据时,可以将集合分割为多个小集合进行逐一处理。

4.1.4 例子

以下是一些示例代码,展示如何使用 CollectionUtils 进行集合操作:

java 复制代码
import org.apache.commons.collections4.CollectionUtils;

List<String> myList = new ArrayList<>(Arrays.asList("one", "two", "three"));

// 判断是否为空
if (CollectionUtils.isEmpty(myList)) {
    System.out.println("列表为空");
}

// 批量添加元素
CollectionUtils.addAll(myList, "four", "five");

// 根据条件过滤集合
Predicate<String> predicate = input -> input.length() > 3;
List<String> filtered = (List<String>) CollectionUtils.select(myList, predicate);

// 转换集合元素为其长度
Transformation<String, Integer> transformation = String::length;
List<Integer> lengths = (List<Integer>) CollectionUtils.collect(myList, transformation);

// 获取两个集合的并集
List<String> otherList = Arrays.asList("six", "seven");
Collection<?> union = CollectionUtils.union(myList, otherList);

// 获取两个集合的交集
Collection<?> intersection = CollectionUtils.intersection(myList, otherList);

// 获取两个集合的差集
Collection<?> difference = CollectionUtils.subtract(myList, otherList);

// 根据条件将集合分割为两个子集合
Map<Boolean, List<String>> partitioned = CollectionUtils.partition(myList, s -> s.length() > 3);

4.2. Predicate 和 Closure

PredicateClosure 是 Apache Commons Collections4 中提供的两个重要概念,旨在简化集合操作,提升代码的可读性和灵活性。

4.2.1 Predicate

Predicate 是一个函数式接口,表示一个接受单个输入参数并返回布尔值的逻辑条件。它通常用于过滤集合中的元素。

主要功能
  • 条件筛选 :使用 Predicate 定义筛选条件,结合集合操作方法(如 selectremoveIf),从集合中选择或删除符合条件的元素。
  • 组合条件 :支持将多个 Predicate 组合在一起,形成复杂的条件逻辑。
常用方法
  • test(T t) :接受一个输入参数,返回 truefalse,用于判断该参数是否符合条件。
java 复制代码
Predicate<String> isLongerThanThree = str -> str.length() > 3;
boolean result = isLongerThanThree.test("Hello"); // true
使用场景
  • 集合过滤 :在处理集合时,可以使用 Predicate 对集合中的元素进行条件筛选。
java 复制代码
List<String> myList = Arrays.asList("one", "two", "three", "four");
List<String> filteredList = (List<String>) CollectionUtils.select(myList, isLongerThanThree);

4.2.2 Closure

Closure 是另一个函数式接口,表示一个接受输入参数并不返回值的操作。它通常用于对集合中的每个元素执行某种操作。

主要功能
  • 操作执行:允许对集合中的每个元素执行特定的操作(例如打印、修改等)。
  • 无需返回值 :与 Predicate 不同,Closure 不需要返回值,可以用于执行副作用操作。
常用方法
  • execute(T input):接受一个输入参数,对其执行某种操作,通常用于副作用逻辑。
java 复制代码
Closure<String> printClosure = str -> System.out.println(str);
printClosure.execute("Hello, World!"); // 输出 "Hello, World!"
使用场景
  • 集合遍历 :在遍历集合时,可以使用 Closure 对每个元素执行操作,而无需关心返回值。
java 复制代码
List<String> myList = Arrays.asList("one", "two", "three");
CollectionUtils.forAllDo(myList, printClosure); // 输出每个元素

4.2.3 示例代码

以下示例展示了如何使用 PredicateClosure 进行集合操作:

java 复制代码
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Closure;

import java.util.Arrays;
import java.util.List;

public class PredicateClosureExample {
    public static void main(String[] args) {
        List<String> myList = Arrays.asList("one", "two", "three", "four");

        // 使用 Predicate 过滤集合
        Predicate<String> isLongerThanThree = str -> str.length() > 3;
        List<String> filteredList = (List<String>) CollectionUtils.select(myList, isLongerThanThree);
        System.out.println("Filtered List: " + filteredList); // 输出: [four]

        // 使用 Closure 打印集合中的元素
        Closure<String> printClosure = str -> System.out.println(str);
        CollectionUtils.forAllDo(myList, printClosure);
    }
}

4.3. MultiMap

MultiMap 是 Apache Commons Collections4 提供的一种特殊的集合,它允许一个键映射到多个值。与标准的 Map 不同,MultiMap 解决了多个值存储的问题,使得在存储和操作关联数据时更加高效和便捷。

4.3.1 基本概念

  • 键-值对 :在 MultiMap 中,键是唯一的,而每个键可以关联多个值。这种特性使得它非常适合于处理一对多的关系。
  • 值的集合 :每个键的值通常存储在一个集合中,如 ListSet,允许重复值或不重复值的选择。

4.3.2 实现类

Apache Commons Collections4 提供了几种实现 MultiMap 接口的具体类,包括:

  • ListMultiMap :每个键映射到一个 List,允许重复值。
  • SetMultiMap :每个键映射到一个 Set,不允许重复值。
  • BagMultiMap :每个键映射到一个 Bag,允许重复值,并提供元素计数功能。

4.3.3 常用方法

MultiMap 接口提供了一些基本的方法,便于操作键和值:

  • put(K key, V value):将值添加到指定键的值集合中。如果键不存在,则会创建一个新的值集合。
  • remove(K key, V value):从指定键的值集合中移除给定值。如果值集合为空,则键也会被删除。
  • get(K key):获取与指定键关联的值集合。
  • keySet() :返回 MultiMap 中所有的键。
  • values() :返回 MultiMap 中所有的值集合。

4.3.4 示例代码

以下示例演示了如何使用 MultiMap 进行常见操作:

java 复制代码
import org.apache.commons.collections4.MultiMap;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.list.SetUniqueList;

import java.util.List;

public class MultiMapExample {
    public static void main(String[] args) {
        // 创建一个 ListMultiMap 实例
        MultiValuedMap<String, String> multiMap = MultiValuedMap.multiValuedMap();
        
        // 添加值
        multiMap.put("Fruit", "Apple");
        multiMap.put("Fruit", "Banana");
        multiMap.put("Fruit", "Apple"); // 允许重复
        multiMap.put("Vegetable", "Carrot");
        
        // 获取与键关联的值集合
        List<String> fruits = (List<String>) multiMap.get("Fruit");
        System.out.println("Fruits: " + fruits); // 输出: Fruits: [Apple, Banana, Apple]

        // 移除特定值
        multiMap.remove("Fruit", "Apple");
        System.out.println("Fruits after removal: " + fruits); // 输出: Fruits after removal: [Banana, Apple]
        
        // 遍历所有键和值
        for (String key : multiMap.keySet()) {
            System.out.println("Key: " + key + ", Values: " + multiMap.get(key));
        }
    }
}

4.3.5 使用场景

MultiMap 在以下场景中非常有用:

  • 一对多关系:当一个实体需要关联多个值时,例如学生和他们的课程、用户和他们的地址等。
  • 数据分组 :在处理分组数据时,可以使用 MultiMap 来轻松管理和访问分组内的所有元素。
  • 简化数据结构 :避免使用嵌套的 MapList,通过 MultiMap 简化数据结构,提高代码的可读性。

4.4. ListUtils

ListUtils 是 Apache Commons Collections4 提供的一个工具类,专门用于操作 List 集合。该类包含了多个静态方法,方便开发者进行常见的列表操作,如合并、排序、查找、过滤等。

4.4.1 基本功能

  1. 合并列表

    • union:返回两个列表的合并结果,去除重复元素。
    • intersection:返回两个列表的交集,包含出现在两个列表中的元素。
    • subtract:返回第一个列表中存在但在第二个列表中不存在的元素。
    • disjunction:返回两个列表的对称差集,即只出现在其中一个列表中的元素。
  2. 查找和过滤

    • select:根据给定的条件过滤列表,返回满足条件的子集。
    • reject :与 select 相反,返回不满足条件的子集。
    • indexOf :查找某个元素在列表中的索引,若不存在则返回 -1
    • lastIndexOf:查找某个元素最后一次出现的索引。
  3. 列表操作

    • reverse:反转列表的元素顺序。
    • rotate:将列表的元素循环移动指定的次数。
    • toArray:将列表转换为数组。
  4. 组合与分组

    • partition:将列表分成固定大小的多个子列表。
    • collate:合并两个已排序的列表,返回一个新的排序列表。
  5. 其它辅助功能

    • isEmpty:检查列表是否为空。
    • addAll:将多个元素添加到列表中。
    • removeAll:从列表中移除多个元素。

4.4.2 示例代码

以下示例展示了 ListUtils 的一些常用方法:

java 复制代码
import org.apache.commons.collections4.ListUtils;

import java.util.Arrays;
import java.util.List;

public class ListUtilsExample {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("Apple", "Banana", "Cherry");
        List<String> list2 = Arrays.asList("Banana", "Date", "Fig");

        // 合并列表
        List<String> union = ListUtils.union(list1, list2);
        System.out.println("Union: " + union); // 输出: [Apple, Banana, Cherry, Date, Fig]

        // 交集
        List<String> intersection = ListUtils.intersection(list1, list2);
        System.out.println("Intersection: " + intersection); // 输出: [Banana]

        // 差集
        List<String> subtract = ListUtils.subtract(list1, list2);
        System.out.println("Subtract: " + subtract); // 输出: [Apple, Cherry]

        // 对称差集
        List<String> disjunction = ListUtils.disjunction(list1, list2);
        System.out.println("Disjunction: " + disjunction); // 输出: [Apple, Cherry, Date, Fig]

        // 过滤列表
        List<String> selected = ListUtils.select(list1, s -> s.startsWith("B"));
        System.out.println("Selected: " + selected); // 输出: [Banana]

        // 反转列表
        List<String> reversed = ListUtils.reverse(list1);
        System.out.println("Reversed: " + reversed); // 输出: [Cherry, Banana, Apple]

        // 分组
        List<List<String>> partitioned = ListUtils.partition(list1, 2);
        System.out.println("Partitioned: " + partitioned); // 输出: [[Apple, Banana], [Cherry]]

        // 将列表转换为数组
        String[] array = ListUtils.toArray(list1, new String[0]);
        System.out.println("Array: " + Arrays.toString(array)); // 输出: [Apple, Banana, Cherry]
    }
}

4.4.3 使用场景

  • 数据处理 :在处理数据集时,合并、交集和差集操作十分常见,使用 ListUtils 可以大大简化代码。
  • 过滤与查找 :当需要从大数据集中查找符合条件的数据时,selectreject 方法提供了有效的解决方案。
  • 列表管理 :管理 List 的顺序和分组,使数据处理更加灵活和高效。

4.5. MapUtils

MapUtils 是 Apache Commons Collections4 提供的一个工具类,专门用于操作 Map 集合。该类包含了多个静态方法,用于简化对 Map 的常见操作,如查找、合并、过滤等。

4.5.1 基本功能

  1. 安全访问

    • get :根据给定的键从 Map 中安全地获取值。如果键不存在,返回指定的默认值,避免 NullPointerException
    • getWithDefault:返回与键对应的值,如果键不存在则返回指定的默认值。
  2. 空值检查

    • isEmpty :检查 Map 是否为空。
    • isNotEmpty :检查 Map 是否不为空。
  3. 合并和更新

    • putAll :将另一个 Map 中的所有键值对添加到当前 Map 中。
    • putIfAbsent :仅在指定的键不存在时,将指定的键值对放入 Map
  4. 查找和过滤

    • filter :根据给定的条件过滤 Map 中的键值对,返回满足条件的子 Map
    • keySet :返回 Map 中的键的集合。
    • values :返回 Map 中的值的集合。
  5. 转换和比较

    • toString :将 Map 转换为字符串形式,便于调试。
    • equals :比较两个 Map 是否相等,支持自定义比较规则。
  6. 迭代操作

    • forEach :对 Map 的每个键值对执行给定的操作,类似于 Java 8 中的 forEach 方法。
    • mapIterator :返回 Map 的迭代器,可以遍历 Map 中的键值对。

4.5.2 示例代码

以下示例展示了 MapUtils 的一些常用方法:

java 复制代码
import org.apache.commons.collections4.MapUtils;

import java.util.HashMap;
import java.util.Map;

public class MapUtilsExample {
    public static void main(String[] args) {
        Map<String, String> map1 = new HashMap<>();
        map1.put("A", "Apple");
        map1.put("B", "Banana");
        
        Map<String, String> map2 = new HashMap<>();
        map2.put("C", "Cherry");
        map2.put("B", "Berry");

        // 安全获取值
        String value = MapUtils.get(map1, "A", "Default");
        System.out.println("Value for key 'A': " + value); // 输出: Apple

        // 合并两个 Map
        MapUtils.putAll(map1, map2);
        System.out.println("Merged Map: " + map1); // 输出: {A=Apple, B=Berry, C=Cherry}

        // 空值检查
        boolean isEmpty = MapUtils.isEmpty(map1);
        System.out.println("Is map1 empty? " + isEmpty); // 输出: false

        // 过滤 Map
        Map<String, String> filteredMap = MapUtils.filter(map1, (key, value1) -> key.equals("A"));
        System.out.println("Filtered Map: " + filteredMap); // 输出: {A=Apple}

        // 转换为字符串
        String mapString = MapUtils.toString(map1);
        System.out.println("Map as String: " + mapString); // 输出: {A=Apple, B=Berry, C=Cherry}

        // 遍历 Map
        MapUtils.forEach(map1, (key, value1) -> System.out.println(key + " -> " + value1));
        // 输出:
        // A -> Apple
        // B -> Berry
        // C -> Cherry
    }
}

4.5.3 使用场景

  • 数据管理 :在处理配置或数据存储时,使用 Map 可以方便地查找和存储键值对。
  • 合并操作 :将多个数据源合并为一个 Map,例如在从数据库获取数据后合并成一个配置 Map
  • 过滤和查找:快速获取符合特定条件的子集,如查找所有特定前缀的键。
  • 安全访问 :避免在获取值时出现 NullPointerException,提供默认值处理。

4.6. QueueUtils

QueueUtils 是 Apache Commons Collections4 中提供的一个工具类,专注于操作 Queue 集合。该类包含多个静态方法,用于简化对 Queue 的常见操作,如添加、移除、查询等。

4.6.1 基本功能

  1. 安全操作

    • add:将指定元素添加到队列中,如果队列已满,则抛出异常。
    • offer :尝试将指定元素添加到队列中。如果队列已满,返回 false,而不抛出异常。
    • remove:从队列中移除并返回头元素,如果队列为空则抛出异常。
    • poll :从队列中移除并返回头元素,如果队列为空,则返回 null
  2. 查询操作

    • peek :查看但不移除队列的头元素,如果队列为空,则返回 null
    • size:获取队列中的元素数量。
  3. 遍历和集合操作

    • forEach :对 Queue 中的每个元素执行给定的操作,类似于 Java 8 中的 forEach 方法。
    • toArray:将队列转换为数组,支持指定数组类型。
    • isEmpty:检查队列是否为空。
  4. 集合转换

    • asQueue :将一个普通的集合(如 Collection)转换为 Queue,以便于使用队列特有的操作。
  5. 顺序管理

    • toString:将队列转换为字符串形式,便于调试和查看。

4.6.2 示例代码

以下示例展示了 QueueUtils 的一些常用方法:

java 复制代码
import org.apache.commons.collections4.QueueUtils;

import java.util.LinkedList;
import java.util.Queue;

public class QueueUtilsExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();

        // 添加元素
        QueueUtils.add(queue, "Element 1");
        QueueUtils.add(queue, "Element 2");
        System.out.println("Queue after adding elements: " + queue); // 输出: [Element 1, Element 2]

        // 使用 offer 方法
        boolean added = QueueUtils.offer(queue, "Element 3");
        System.out.println("Was Element 3 added? " + added); // 输出: true

        // 查询头元素
        String headElement = QueueUtils.peek(queue);
        System.out.println("Head element: " + headElement); // 输出: Element 1

        // 移除头元素
        String removedElement = QueueUtils.remove(queue);
        System.out.println("Removed element: " + removedElement); // 输出: Element 1
        System.out.println("Queue after removal: " + queue); // 输出: [Element 2, Element 3]

        // 获取队列大小
        int size = QueueUtils.size(queue);
        System.out.println("Queue size: " + size); // 输出: 2

        // 遍历队列
        QueueUtils.forEach(queue, element -> System.out.println("Queue element: " + element));
        // 输出:
        // Queue element: Element 2
        // Queue element: Element 3

        // 检查是否为空
        boolean isEmpty = QueueUtils.isEmpty(queue);
        System.out.println("Is queue empty? " + isEmpty); // 输出: false

        // 转换为数组
        String[] array = QueueUtils.toArray(queue, new String[0]);
        System.out.println("Queue as array: " + String.join(", ", array)); // 输出: Element 2, Element 3
    }
}

4.6.3 使用场景

  • 任务队列管理:在并发编程或任务调度中,使用队列来管理任务的执行顺序。
  • 事件处理:在事件驱动的系统中,使用队列来缓存待处理的事件。
  • 流控制:在数据流的应用中,使用队列来控制数据的流入和流出,避免数据丢失。

4.7. IterableMap 和 OrderedMap

4.7.1 IterableMap

IterableMap 是 Apache Commons Collections4 中定义的一个接口,它扩展了 Java 的 Map 接口,并添加了一些迭代功能。此接口允许开发者通过 Iterable 接口来遍历映射的条目,而不仅仅是通过传统的 entrySet()keySet()values() 方法。

主要特性:
  • 迭代访问 :可以直接对映射中的条目进行迭代。IterableMap 提供了 iterator() 方法,返回一个 Iterator,可以遍历映射中的条目。
  • 增强的可读性:使代码更简洁,通过增强的迭代支持,减少了不必要的转换步骤。
主要方法:
  • Iterator<Entry<K, V>> iterator():返回一个迭代器,用于遍历映射的条目。
示例代码:
java 复制代码
import org.apache.commons.collections4.IterableMap;
import org.apache.commons.collections4.map.LinkedMap;

public class IterableMapExample {
    public static void main(String[] args) {
        IterableMap<String, Integer> map = new LinkedMap<>();
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);

        for (Entry<String, Integer> entry : map) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

4.7.2 OrderedMap

OrderedMap 是 Apache Commons Collections4 中的另一个接口,扩展了 Map 接口,并提供了按插入顺序维护条目的能力。该接口确保当你遍历 OrderedMap 的时候,条目的顺序与它们被插入的顺序相同。

主要特性:
  • 插入顺序:保证条目的顺序与插入顺序一致,便于处理需要有序数据的场景。
  • 支持双向访问 :可以通过 List 的方式访问映射中的条目,也可以通过 Map 的方式访问,增强了灵活性。
主要方法:
  • List<K> keys():返回一个按插入顺序排列的键的列表。
  • List<V> values():返回一个按插入顺序排列的值的列表。
  • List<Entry<K, V>> entries():返回一个按插入顺序排列的条目列表。
示例代码:
java 复制代码
import org.apache.commons.collections4.OrderedMap;
import org.apache.commons.collections4.map.LinkedMap;

public class OrderedMapExample {
    public static void main(String[] args) {
        OrderedMap<String, Integer> orderedMap = new LinkedMap<>();
        orderedMap.put("One", 1);
        orderedMap.put("Two", 2);
        orderedMap.put("Three", 3);

        System.out.println("Keys in order of insertion: " + orderedMap.keys());
        System.out.println("Values in order of insertion: " + orderedMap.values());

        for (Entry<String, Integer> entry : orderedMap.entries()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

4.7.3 使用场景

  • 需要保持顺序的映射:在处理数据时,需要确保映射中的条目以插入顺序进行处理的场景,如配置参数、历史记录等。
  • 便于迭代访问 :在需要遍历映射中的所有条目时,IterableMap 的设计使得操作更加简洁。

4.8. Trie

Trie 是一种树形数据结构,用于高效存储和检索字符串,尤其适用于前缀匹配的场景。Apache Commons Collections4 提供了 Trie 接口和相关实现,允许开发者使用 Trie 结构来存储字符串集合。

4.8.1 主要特性

  • 前缀搜索:能够快速查找以某个前缀开头的字符串,这使得 Trie 在自动补全和拼写检查等应用中非常有效。
  • 空间效率:Trie 通过共享公共前缀来节省内存,与单独存储每个字符串相比,具有更好的空间效率。
  • 动态插入和删除:Trie 支持动态添加和删除字符串,这对于需要频繁更新的数据集非常有用。

4.8.2 主要方法

以下是 Trie 接口中的一些主要方法:

  • void insert(String word):将一个字符串插入到 Trie 中。
  • boolean contains(String word):检查 Trie 中是否包含某个字符串。
  • List<String> autocomplete(String prefix):返回以给定前缀开头的所有字符串列表。
  • void delete(String word):从 Trie 中删除一个字符串。

4.8.3 实现示例

以下是使用 Trie 的简单示例,展示如何插入字符串、检查是否存在以及进行前缀匹配。

java 复制代码
import org.apache.commons.collections4.trie.PatriciaTrie;

public class TrieExample {
    public static void main(String[] args) {
        PatriciaTrie<String> trie = new PatriciaTrie<>();

        // 插入字符串
        trie.put("apple", "A fruit");
        trie.put("app", "A short form of application");
        trie.put("apricot", "Another fruit");

        // 检查是否包含某个字符串
        System.out.println("Contains 'apple'? " + trie.containsKey("apple")); // true
        System.out.println("Contains 'banana'? " + trie.containsKey("banana")); // false

        // 前缀匹配
        String prefix = "app";
        List<String> suggestions = new ArrayList<>(trie.prefixMap(prefix).keySet());
        System.out.println("Autocomplete suggestions for '" + prefix + "': " + suggestions);
    }
}

4.8.4 使用场景

  • 自动补全:在输入框中,实时给出用户可能输入的选项。
  • 拼写检查:根据用户输入,给出正确的拼写建议。
  • 字典实现:用于词汇表、搜索引擎中的关键词管理等。

4.8.5 性能

  • 插入时间复杂度:O(m),其中 m 是插入字符串的长度。
  • 搜索时间复杂度:O(m),其中 m 是搜索字符串的长度。
  • 空间复杂度:取决于插入的字符串数量及其共同前缀。

Trie 在处理大量字符串时表现出色,特别是当应用程序需要支持高效的前缀搜索时,选择 Trie 结构将极大提高性能。

4.9. ComparatorUtils

ComparatorUtils 是 Apache Commons Collections4 中的一个工具类,提供了一系列静态方法,用于创建和组合比较器(Comparator)。它简化了比较对象的操作,支持各种排序需求。

4.9.1 主要特性

  • 组合比较器:能够将多个比较器组合成一个,从而支持多级排序。
  • 空值处理:提供了对空值的自定义处理选项。
  • 简化的比较器创建:提供了各种方法来快速创建常见的比较器。

4.9.2 主要方法

以下是 ComparatorUtils 中的一些重要方法:

  • Comparator<T> nullsFirst(Comparator<T> comparator):返回一个比较器,该比较器在比较时将空值排在前面。

    java 复制代码
    Comparator<String> comparator = ComparatorUtils.nullsFirst(Comparator.naturalOrder());
  • Comparator<T> nullsLast(Comparator<T> comparator):返回一个比较器,该比较器在比较时将空值排在最后。

    java 复制代码
    Comparator<String> comparator = ComparatorUtils.nullsLast(Comparator.naturalOrder());
  • Comparator<T> chained(Comparator<T>... comparators):返回一个组合比较器,按照提供的比较器顺序进行比较。

    java 复制代码
    Comparator<Person> combinedComparator = ComparatorUtils.chained(
        Comparator.comparing(Person::getLastName),
        Comparator.comparing(Person::getFirstName)
    );
  • Comparator<T> reversed(Comparator<T> comparator):返回一个比较器,该比较器与提供的比较器具有相反的顺序。

    java 复制代码
    Comparator<String> reversedComparator = ComparatorUtils.reversed(Comparator.naturalOrder());

4.9.3 使用示例

以下示例展示了如何使用 ComparatorUtils 来处理多个比较器并进行排序。

java 复制代码
import org.apache.commons.collections4.ComparatorUtils;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class ComparatorUtilsExample {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", null, "Dave");

        // 使用 nullsLast 处理空值
        names.sort(ComparatorUtils.nullsLast(Comparator.naturalOrder()));
        System.out.println("Sorted with nulls last: " + names);

        // 组合比较器
        List<Person> people = Arrays.asList(
            new Person("Alice", "Smith"),
            new Person("Bob", "Johnson"),
            new Person("Alice", "Johnson")
        );

        people.sort(ComparatorUtils.chained(
            Comparator.comparing(Person::getFirstName),
            Comparator.comparing(Person::getLastName)
        ));

        // 输出排序后的结果
        System.out.println("Sorted people: " + people);
    }
}

class Person {
    private String firstName;
    private String lastName;

    // Constructor, getters, and toString() omitted for brevity
}

4.9.4 使用场景

  • 自定义排序:在需要对复杂对象进行多重排序时,使用组合比较器可以简化代码。
  • 空值优先级处理:在排序时处理空值时,能够灵活指定它们的位置。
  • 集合操作:在进行集合排序时,能够简化比较器的创建和使用。

4.9.5 性能

  • 时间复杂度:与排序算法相关,使用组合比较器时,通常保持 O(n log n) 的时间复杂度。
  • 空间复杂度:额外的空间复杂度通常较低,主要用于存储比较器。

4.10. FixedSizeList、LazyList、UnmodifiableList

在 Apache Commons Collections4 中,FixedSizeListLazyListUnmodifiableList 是用于创建不同特性列表的工具类。每个类都有其特定的用途和特点,下面逐一展开说明。

4.10.1 FixedSizeList

FixedSizeList 是一种固定大小的列表实现,它限制了列表的大小,不允许添加或删除元素。这个特性使得它适用于那些对元素数量有严格控制的场合。

  • 创建

    使用 FixedSizeList,可以通过调用 FixedSizeList.fixedSizeList(List<T> list) 方法创建一个固定大小的列表。

    java 复制代码
    List<String> originalList = new ArrayList<>(Arrays.asList("A", "B", "C"));
    List<String> fixedSizeList = FixedSizeList.fixedSizeList(originalList);
  • 行为

    • 尝试添加元素会抛出 UnsupportedOperationException
    • 可以修改列表中的现有元素,但不能更改列表的大小。
    java 复制代码
    fixedSizeList.set(1, "D"); // 修改成功
    fixedSizeList.add("E"); // 抛出异常

4.10.2 LazyList

LazyList 是一种延迟加载的列表实现,只有在访问元素时才会初始化元素。这个特性非常适合处理大型数据集,特别是在需要延迟加载数据以提高性能的情况下。

  • 创建

    使用 LazyList,可以通过调用 LazyList.lazyList(List<T> list, Factory<T> factory) 方法来创建。

    java 复制代码
    List<String> lazyList = LazyList.lazyList(new ArrayList<>(), () -> "defaultValue");
  • 行为

    • 当访问未初始化的元素时,会自动调用提供的工厂方法来初始化该元素。
    • 支持修改和删除元素,但只有在元素被实际访问时才会执行初始化。
    java 复制代码
    String value = lazyList.get(0); // 触发初始化,返回 "defaultValue"
    lazyList.set(0, "New Value"); // 修改元素

4.10.3 UnmodifiableList

UnmodifiableList 是一种不可修改的列表实现,它包装了另一个列表,使其不可变。这种实现适用于需要提供只读访问的场合,确保数据不被修改。

  • 创建

    可以通过调用 UnmodifiableList.unmodifiableList(List<T> list) 方法创建。

    java 复制代码
    List<String> originalList = new ArrayList<>(Arrays.asList("A", "B", "C"));
    List<String> unmodifiableList = UnmodifiableList.unmodifiableList(originalList);
  • 行为

    • 所有对列表的修改操作(如 addremoveset)都会抛出 UnsupportedOperationException
    • 可以安全地在多线程环境中共享,因为列表不会被修改。
    java 复制代码
    unmodifiableList.add("D"); // 抛出异常
    String value = unmodifiableList.get(0); // 允许访问元素

4.10.4 使用示例

以下示例展示了如何使用 FixedSizeListLazyListUnmodifiableList

java 复制代码
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.collections4.list.FixedSizeList;
import org.apache.commons.collections4.list.LazyList;
import org.apache.commons.collections4.list.UnmodifiableList;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ListUtilsExample {
    public static void main(String[] args) {
        // 使用 FixedSizeList
        List<String> originalList = new ArrayList<>(Arrays.asList("A", "B", "C"));
        List<String> fixedSizeList = FixedSizeList.fixedSizeList(originalList);
        
        fixedSizeList.set(0, "Z"); // 修改成功
        System.out.println("FixedSizeList: " + fixedSizeList);
        // fixedSizeList.add("D"); // 抛出异常

        // 使用 LazyList
        List<String> lazyList = LazyList.lazyList(new ArrayList<>(), () -> "defaultValue");
        
        String value = lazyList.get(0); // 触发初始化
        System.out.println("LazyList first element: " + value); // 输出 "defaultValue"
        
        lazyList.set(0, "New Value"); // 修改元素
        System.out.println("LazyList first element after modification: " + lazyList.get(0));

        // 使用 UnmodifiableList
        List<String> unmodifiableList = UnmodifiableList.unmodifiableList(originalList);
        
        // unmodifiableList.add("D"); // 抛出异常
        System.out.println("UnmodifiableList: " + unmodifiableList);
    }
}

4.10.5 使用场景

  • FixedSizeList:适合需要限制大小的场景,例如实现固定大小的缓存。
  • LazyList:适用于延迟加载数据的场合,可以减少内存消耗和提升性能。
  • UnmodifiableList:适合需要提供只读视图的场景,如防止数据被意外修改。

5. 扩展阅读

相关推荐
苹果醋317 分钟前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
Hello.Reader37 分钟前
深入解析 Apache APISIX
java·apache
菠萝蚊鸭1 小时前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
007php0071 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
∝请叫*我简单先生1 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
ssr——ssss1 小时前
SSM-期末项目 - 基于SSM的宠物信息管理系统
java·ssm
一棵星2 小时前
Java模拟Mqtt客户端连接Mqtt Broker
java·开发语言
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#
zquwei2 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring