The Apache Commons Collections package contains types that extend and augment the Java Collections Framework
npx @tessl/cli install tessl/maven-org-apache-commons--commons-collections4@4.5.0Apache Commons Collections 4 is a comprehensive Java library that extends and enhances the Java Collections Framework with powerful data structures, algorithms, and utilities. It provides advanced collection types, functional programming support, and extensive utility methods for working with collections.
Apache Commons Collections 4 extends the Java Collections Framework by providing:
The library is organized into 19 packages covering core collection types, specialized data structures, functional programming utilities, and comprehensive helper classes.
pom.xml:<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0</version>
</dependency>// Core interfaces and utilities
import org.apache.commons.collections4.*;
// Bag collections
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.bag.HashBag;
import org.apache.commons.collections4.bag.TreeBag;
// Bidirectional maps
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
import org.apache.commons.collections4.bidimap.TreeBidiMap;
// Multi-valued maps
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
// Functional interfaces
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.Closure;
import org.apache.commons.collections4.Factory;
// Utility classes
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.collections4.SetUtils;import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.bag.HashBag;
// Create a bag to count occurrences
Bag<String> bag = new HashBag<>();
bag.add("apple", 3);
bag.add("banana", 2);
bag.add("apple"); // Now apple has count of 4
// Get counts
int appleCount = bag.getCount("apple"); // Returns 4
int totalItems = bag.size(); // Returns 6 (3+2+1)
int uniqueItems = bag.uniqueSet().size(); // Returns 2
// Check contents
boolean hasApple = bag.contains("apple");
boolean hasPear = bag.contains("pear"); // falseimport org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
// Create bidirectional map
BidiMap<String, Integer> bidiMap = new DualHashBidiMap<>();
bidiMap.put("one", 1);
bidiMap.put("two", 2);
bidiMap.put("three", 3);
// Lookup by key (normal map operation)
Integer value = bidiMap.get("two"); // Returns 2
// Lookup by value (reverse lookup)
String key = bidiMap.getKey(2); // Returns "two"
// Get inverse view
BidiMap<Integer, String> inverseMap = bidiMap.inverseBidiMap();
String keyFromInverse = inverseMap.get(3); // Returns "three"import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import java.util.Collection;
// Create multi-valued map
MultiValuedMap<String, String> multiMap = new ArrayListValuedHashMap<>();
multiMap.put("colors", "red");
multiMap.put("colors", "green");
multiMap.put("colors", "blue");
multiMap.put("animals", "cat");
multiMap.put("animals", "dog");
// Get all values for a key
Collection<String> colors = multiMap.get("colors"); // [red, green, blue]
// Check size
int totalMappings = multiMap.size(); // Returns 5
int uniqueKeys = multiMap.keySet().size(); // Returns 2
// Remove specific mapping
boolean removed = multiMap.removeMapping("colors", "red");import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Predicate;
import java.util.List;
import java.util.Arrays;
import java.util.Collection;
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8);
// Set operations
Collection<Integer> union = CollectionUtils.union(list1, list2); // [1,2,3,4,5,6,7,8]
Collection<Integer> intersection = CollectionUtils.intersection(list1, list2); // [4,5]
Collection<Integer> difference = CollectionUtils.subtract(list1, list2); // [1,2,3]
// Filtering with predicates
Predicate<Integer> evenPredicate = n -> n % 2 == 0;
Collection<Integer> evenNumbers = CollectionUtils.select(list1, evenPredicate); // [2,4]
// Null-safe operations
boolean isEmpty = CollectionUtils.isEmpty(null); // true
boolean isNotEmpty = CollectionUtils.isNotEmpty(list1); // trueimport org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.CollectionUtils;
import java.util.List;
import java.util.Arrays;
import java.util.Collection;
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// Create predicates
Predicate<String> longNamePredicate = name -> name.length() > 4;
Predicate<String> startsWithC = name -> name.startsWith("C");
// Create transformer
Transformer<String, String> upperCaseTransformer = String::toUpperCase;
// Apply filtering
Collection<String> longNames = CollectionUtils.select(names, longNamePredicate); // [Alice, Charlie]
// Apply transformation
Collection<String> upperCaseNames = CollectionUtils.collect(names, upperCaseTransformer); // [ALICE, BOB, CHARLIE, DAVID]
// Chain operations
Collection<String> longUpperCaseNames = CollectionUtils.collect(
CollectionUtils.select(names, longNamePredicate),
upperCaseTransformer
); // [ALICE, CHARLIE]import org.apache.commons.collections4.FluentIterable;
import java.util.List;
import java.util.Arrays;
List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
// Fluent chain operations
List<String> result = FluentIterable.of(words)
.filter(word -> word.length() > 4) // Keep words longer than 4 chars
.transform(String::toUpperCase) // Transform to uppercase
.limit(2) // Take first 2 results
.toList(); // Convert to list
// Result: [APPLE, BANANA]
// Check conditions
boolean allLong = FluentIterable.of(words)
.allMatch(word -> word.length() > 2); // true
boolean anyStartsWithA = FluentIterable.of(words)
.anyMatch(word -> word.startsWith("a")); // trueApache Commons Collections 4 follows several key design patterns:
Collections can be wrapped with decorators that add functionality:
import org.apache.commons.collections4.list.PredicatedList;
import org.apache.commons.collections4.list.SynchronizedList;
import org.apache.commons.collections4.list.UnmodifiableList;
import java.util.List;
import java.util.ArrayList;
List<String> baseList = new ArrayList<>();
// Add predicate validation - only allows non-null strings
List<String> predicatedList = PredicatedList.predicatedList(baseList, Objects::nonNull);
// Add thread safety
List<String> synchronizedList = SynchronizedList.synchronizedList(predicatedList);
// Make unmodifiable
List<String> unmodifiableList = UnmodifiableList.unmodifiableList(synchronizedList);Utility classes provide factory methods for creating enhanced collections:
import org.apache.commons.collections4.BagUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.bag.HashBag;
import java.util.Map;
import java.util.HashMap;
// Create synchronized collections
Bag<String> synchronizedBag = BagUtils.synchronizedBag(new HashBag<>());
// Create lazy maps (values created on first access)
Map<String, List<String>> lazyMap = MapUtils.lazyMap(
new HashMap<>(),
() -> new ArrayList<>()
);Abstract base classes provide common functionality while allowing customization:
AbstractMapBag - Base for bag implementationsAbstractBidiMap - Base for bidirectional map implementationsAbstractMultiValuedMap - Base for multi-valued map implementationsFunctional interfaces allow pluggable behavior:
Predicate<T> - Testing strategyTransformer<T, R> - Transformation strategyClosure<T> - Action strategyFactory<T> - Creation strategyCollections that track element occurrence counts, useful for frequency analysis and statistical operations.
Maps supporting efficient bidirectional lookup between keys and values with 1:1 relationships.
Maps that associate multiple values with each key, supporting both List and Set semantics.
Specialized collections including tries, bloom filters, queues, and iterators for specific use cases.
Comprehensive support for functional-style programming with predicates, transformers, closures, and factories.
Extensive utility methods for collection operations, transformations, and manipulations.
All classes and interfaces in Apache Commons Collections 4 are fully generic-enabled:
// Type-safe bag operations
Bag<Person> people = new HashBag<>();
people.add(new Person("Alice"));
int count = people.getCount(new Person("Alice"));
// Type-safe transformations
Transformer<Person, String> nameExtractor = Person::getName;
Collection<String> names = CollectionUtils.collect(people, nameExtractor);
// Type-safe predicates
Predicate<Person> adultPredicate = person -> person.getAge() >= 18;
Collection<Person> adults = CollectionUtils.select(people, adultPredicate);Commons Collections provides thread-safe wrappers for all collection types:
// Thread-safe collections
Map<String, Object> safeMap = MapUtils.synchronizedMap(new HashMap<>());
List<String> safeList = ListUtils.synchronizedList(new ArrayList<>());
Set<String> safeSet = SetUtils.synchronizedSet(new HashSet<>());
Bag<String> safeBag = BagUtils.synchronizedBag(new HashBag<>());
// Note: Iteration still requires external synchronization
synchronized(safeList) {
for(String item : safeList) {
// Safe iteration
}
}Different implementations provide different performance characteristics:
Choose implementations based on your specific requirements for speed, memory usage, and ordering guarantees.
Apache Commons Collections 4 provides significant improvements over version 3.x:
For migration guidance, see the official migration documentation and RELEASE-NOTES.txt in the source distribution.