CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apache-commons--commons-collections4

The Apache Commons Collections package contains types that extend and augment the Java Collections Framework

Pending
Overview
Eval results
Files

advanced-collections.mddocs/

Advanced Collections

Apache Commons Collections provides several specialized collection types for specific use cases including tries (prefix trees), bloom filters, advanced queues, and sophisticated iterators.

Trie Collections (Prefix Trees)

Tries are tree-based data structures optimized for prefix-based operations on strings or sequences.

Trie<K, V> Interface

import org.apache.commons.collections4.Trie;
import org.apache.commons.collections4.trie.PatriciaTrie;
import java.util.SortedMap;

Trie<String, Integer> trie = new PatriciaTrie<>();

// Add key-value pairs
trie.put("cat", 1);
trie.put("car", 2);
trie.put("card", 3);
trie.put("care", 4);
trie.put("careful", 5);
trie.put("dog", 6);

// Standard map operations
Integer value = trie.get("car");                    // Returns 2
boolean hasKey = trie.containsKey("card");          // true
int size = trie.size();                             // 6

// Prefix-based operations
SortedMap<String, Integer> carPrefixed = trie.prefixMap("car");
// Returns: {car=2, card=3, care=4, careful=5}

SortedMap<String, Integer> cPrefixed = trie.prefixMap("c");
// Returns: {car=2, card=3, care=4, careful=5, cat=1}

// Empty prefix returns all entries
SortedMap<String, Integer> all = trie.prefixMap("");

PatriciaTrie<V> Implementation

PATRICIA (Practical Algorithm to Retrieve Information Coded in Alphanumeric) trie implementation.

import org.apache.commons.collections4.trie.PatriciaTrie;
import java.util.Map;

// Create for String keys
PatriciaTrie<String> dictionary = new PatriciaTrie<>();

// Add dictionary entries
dictionary.put("apple", "A red or green fruit");
dictionary.put("application", "A software program");
dictionary.put("apply", "To put to use");
dictionary.put("appreciate", "To value or understand");

// Autocomplete functionality
SortedMap<String, String> suggestions = dictionary.prefixMap("app");
System.out.println("Words starting with 'app':");
suggestions.forEach((word, definition) -> 
    System.out.println(word + ": " + definition));

// Create from existing map
Map<String, Integer> wordCounts = Map.of(
    "hello", 5,
    "world", 3,
    "help", 2,
    "helper", 1
);
PatriciaTrie<Integer> countTrie = new PatriciaTrie<>(wordCounts);

// Find all words with "hel" prefix
SortedMap<String, Integer> helWords = countTrie.prefixMap("hel");
// Returns: {hello=5, help=2, helper=1}

Trie Use Cases

Autocomplete System

public class AutocompleteSystem {
    private final Trie<String, Integer> trie = new PatriciaTrie<>();
    
    public void addWord(String word, int frequency) {
        trie.put(word.toLowerCase(), frequency);
    }
    
    public List<String> getSuggestions(String prefix, int maxResults) {
        SortedMap<String, Integer> matches = trie.prefixMap(prefix.toLowerCase());
        
        return matches.entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) // Sort by frequency
            .limit(maxResults)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
    }
    
    public boolean hasWord(String word) {
        return trie.containsKey(word.toLowerCase());
    }
    
    public void incrementFrequency(String word) {
        String key = word.toLowerCase();
        int currentFreq = trie.getOrDefault(key, 0);
        trie.put(key, currentFreq + 1);
    }
}

Phone Directory

public class PhoneDirectory {
    private final Trie<String, Contact> byName = new PatriciaTrie<>();
    private final Trie<String, Contact> byPhone = new PatriciaTrie<>();
    
    public void addContact(Contact contact) {
        byName.put(contact.getName().toLowerCase(), contact);
        byPhone.put(contact.getPhone(), contact);
    }
    
    public List<Contact> searchByName(String namePrefix) {
        return new ArrayList<>(byName.prefixMap(namePrefix.toLowerCase()).values());
    }
    
    public List<Contact> searchByPhone(String phonePrefix) {
        return new ArrayList<>(byPhone.prefixMap(phonePrefix).values());
    }
    
    public Contact getExactMatch(String name) {
        return byName.get(name.toLowerCase());
    }
}

Bloom Filters

Probabilistic data structures for membership testing with no false negatives but possible false positives.

BloomFilter Interface

import org.apache.commons.collections4.bloomfilter.BloomFilter;
import org.apache.commons.collections4.bloomfilter.SimpleBloomFilter;
import org.apache.commons.collections4.bloomfilter.Shape;
import org.apache.commons.collections4.bloomfilter.Hasher;
import org.apache.commons.collections4.bloomfilter.EnhancedDoubleHasher;

// Create bloom filter shape (size and hash functions)
Shape shape = Shape.fromEstimates(1000, 0.01); // Expected elements: 1000, false positive rate: 1%

BloomFilter filter = new SimpleBloomFilter(shape);

// Add elements (using hashers)
Hasher hasher1 = new EnhancedDoubleHasher("element1".hashCode(), "element1".hashCode());
Hasher hasher2 = new EnhancedDoubleHasher("element2".hashCode(), "element2".hashCode());

filter.merge(hasher1);
filter.merge(hasher2);

// Test membership
boolean mayContain1 = filter.contains(hasher1);  // true (definitely in set)
Hasher hasher3 = new EnhancedDoubleHasher("element3".hashCode(), "element3".hashCode());
boolean mayContain3 = filter.contains(hasher3);  // false or true (maybe in set)

// Get filter statistics
int cardinality = filter.cardinality();          // Number of set bits
Shape filterShape = filter.getShape();           // Configuration details

CountingBloomFilter Interface

Allows removal of elements by maintaining counts.

import org.apache.commons.collections4.bloomfilter.CountingBloomFilter;

CountingBloomFilter countingFilter = new ArrayCountingBloomFilter(shape);

// Add elements
countingFilter.merge(hasher1);
countingFilter.merge(hasher1); // Add same element twice

// Remove elements  
boolean removed = countingFilter.remove(hasher1); // Decrements count
boolean removedAgain = countingFilter.remove(hasher1); // Decrements to zero

// Element no longer in filter
boolean stillThere = countingFilter.contains(hasher1); // false

Bloom Filter Use Cases

Caching Layer

public class CacheWithBloomFilter<K, V> {
    private final Map<K, V> cache = new HashMap<>();
    private final BloomFilter filter;
    private final Function<K, Hasher> hasherFunction;
    
    public CacheWithBloomFilter(Shape shape, Function<K, Hasher> hasherFunction) {
        this.filter = new SimpleBloomFilter(shape);
        this.hasherFunction = hasherFunction;
    }
    
    public void put(K key, V value) {
        cache.put(key, value);
        filter.merge(hasherFunction.apply(key));
    }
    
    public V get(K key) {
        // Fast negative check - if not in bloom filter, definitely not in cache
        if (!filter.contains(hasherFunction.apply(key))) {
            return null; // Definitely not in cache
        }
        
        // May or may not be in cache - check actual cache
        return cache.get(key);
    }
    
    public boolean mightContain(K key) {
        return filter.contains(hasherFunction.apply(key));
    }
}

Additional Bloom Filter Implementations

Apache Commons Collections provides several specialized bloom filter implementations for different use cases.

import org.apache.commons.collections4.bloomfilter.ArrayCountingBloomFilter;
import org.apache.commons.collections4.bloomfilter.BitMapBloomFilter;
import org.apache.commons.collections4.bloomfilter.LayeredBloomFilter;

// Array-based counting bloom filter (supports removal)
ArrayCountingBloomFilter countingFilter = new ArrayCountingBloomFilter(shape);
countingFilter.merge(hasher1);
countingFilter.merge(hasher1); // Add twice
boolean removed = countingFilter.remove(hasher1); // Remove once

// Bitmap-based bloom filter for memory efficiency
BitMapBloomFilter bitMapFilter = new BitMapBloomFilter(shape);
bitMapFilter.merge(hasher1);
boolean contains = bitMapFilter.contains(hasher1); // Fast membership test

// Layered bloom filter for time-based data
LayeredBloomFilter layeredFilter = new LayeredBloomFilter(shape, 3); // 3 layers
layeredFilter.merge(hasher1);
layeredFilter.next(); // Advance to next layer
layeredFilter.merge(hasher2);

Bloom Filter Shape Configuration

The Shape class configures bloom filter parameters for optimal performance.

import org.apache.commons.collections4.bloomfilter.Shape;

// Create shape from estimates
Shape fromEstimates = Shape.fromEstimates(1000, 0.01); // 1000 items, 1% false positive rate

// Create shape from parameters
Shape fromParams = Shape.fromNP(1000, 10); // 1000 items, 10 hash functions

// Get shape properties
int numberOfBits = fromEstimates.getNumberOfBits();       // Total bits in filter
int numberOfHashFunctions = fromEstimates.getNumberOfHashFunctions(); // Hash functions used
double probability = fromEstimates.getProbability(500);   // False positive rate at 500 items

// Calculate optimal parameters for different scenarios
int optimalBits = Shape.calculateNumberOfBits(1000, 0.01);      // Bits needed
int optimalHashes = Shape.calculateNumberOfHashFunctions(1000, 9600); // Hash functions needed

Advanced Queue Implementations

CircularFifoQueue<E>

A fixed-size queue that overwrites the oldest element when full.

import org.apache.commons.collections4.queue.CircularFifoQueue;

// Create with default size (32)
CircularFifoQueue<String> defaultQueue = new CircularFifoQueue<>();

// Create with specific size
CircularFifoQueue<Integer> numbers = new CircularFifoQueue<>(5);

// Add elements
numbers.offer(1);
numbers.offer(2);
numbers.offer(3);
numbers.offer(4);
numbers.offer(5);

System.out.println(numbers); // [1, 2, 3, 4, 5]

// Adding when full overwrites oldest
numbers.offer(6); // Overwrites 1
numbers.offer(7); // Overwrites 2

System.out.println(numbers); // [3, 4, 5, 6, 7]

// Queue properties
boolean isFull = numbers.isFull();           // true
int maxSize = numbers.maxSize();             // 5
int currentSize = numbers.size();            // 5

// Create from existing collection (takes only last N elements if oversized)
List<String> manyItems = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
CircularFifoQueue<String> fromList = new CircularFifoQueue<>(manyItems); // Takes last 32
CircularFifoQueue<String> fromListSized = new CircularFifoQueue<>(3, manyItems); // Takes "f", "g", "h"

Queue Decorators

import org.apache.commons.collections4.QueueUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;
import java.util.LinkedList;
import java.util.Queue;

Queue<String> baseQueue = new LinkedList<>();

// Synchronized queue
Queue<String> syncQueue = QueueUtils.synchronizedQueue(baseQueue);

// Unmodifiable queue
baseQueue.offer("item1");
baseQueue.offer("item2");
Queue<String> readOnlyQueue = QueueUtils.unmodifiableQueue(baseQueue);

// Predicated queue (validates additions)
Predicate<String> nonEmpty = s -> s != null && !s.trim().isEmpty();
Queue<String> validatedQueue = QueueUtils.predicatedQueue(new LinkedList<>(), nonEmpty);

validatedQueue.offer("valid");     // Success
try {
    validatedQueue.offer("");      // Throws IllegalArgumentException
} catch (IllegalArgumentException e) {
    System.out.println("Empty string rejected");
}

// Transforming queue
Transformer<String, String> upperCase = String::toUpperCase;
Queue<String> transformingQueue = QueueUtils.transformingQueue(new LinkedList<>(), upperCase);
transformingQueue.offer("hello"); // Stored as "HELLO"

Specialized Queue Use Cases

Recent Items Cache

public class RecentItemsCache<T> {
    private final CircularFifoQueue<T> recentItems;
    private final Set<T> itemSet = new LinkedHashSet<>();
    
    public RecentItemsCache(int maxSize) {
        this.recentItems = new CircularFifoQueue<>(maxSize);
    }
    
    public void addItem(T item) {
        // Remove if already exists to avoid duplicates
        if (itemSet.contains(item)) {
            recentItems.remove(item);
            itemSet.remove(item);
        }
        
        // Add new item
        if (recentItems.isFull()) {
            T removed = recentItems.poll();
            itemSet.remove(removed);
        }
        
        recentItems.offer(item);
        itemSet.add(item);
    }
    
    public List<T> getRecentItems() {
        return new ArrayList<>(recentItems);
    }
    
    public boolean isRecent(T item) {
        return itemSet.contains(item);
    }
}

Advanced Iterators

Specialized Iterator Types

OrderedIterator<E>

Iterator that supports bidirectional navigation.

import org.apache.commons.collections4.OrderedIterator;
import org.apache.commons.collections4.iterators.ListIteratorWrapper;
import java.util.List;
import java.util.Arrays;

List<String> list = Arrays.asList("first", "second", "third", "fourth");
OrderedIterator<String> iterator = new ListIteratorWrapper<>(list.listIterator());

// Forward iteration
while (iterator.hasNext()) {
    String item = iterator.next();
    System.out.println("Forward: " + item);
}

// Backward iteration
while (iterator.hasPrevious()) {
    String item = iterator.previous();
    System.out.println("Backward: " + item);
}

ResettableIterator<E>

Iterator that can be reset to its initial position.

import org.apache.commons.collections4.ResettableIterator;
import org.apache.commons.collections4.iterators.ArrayIterator;

String[] array = {"a", "b", "c", "d"};
ResettableIterator<String> resetIterator = new ArrayIterator<>(array);

// First iteration
while (resetIterator.hasNext()) {
    System.out.println("First pass: " + resetIterator.next());
}

// Reset and iterate again
resetIterator.reset();
while (resetIterator.hasNext()) {
    System.out.println("Second pass: " + resetIterator.next());
}

MapIterator<K, V>

Iterator optimized for map traversal.

import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.map.LinkedMap;

LinkedMap<String, Integer> map = new LinkedMap<>();
map.put("apple", 5);
map.put("banana", 3);
map.put("cherry", 8);

MapIterator<String, Integer> mapIterator = map.mapIterator();
while (mapIterator.hasNext()) {
    String key = mapIterator.next();
    Integer value = mapIterator.getValue();
    
    // Modify value in-place
    mapIterator.setValue(value * 2);
    
    System.out.println(key + " -> " + mapIterator.getValue());
}

Iterator Utilities

Chaining Iterators

import org.apache.commons.collections4.IteratorUtils;
import java.util.Iterator;
import java.util.Arrays;

List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("d", "e", "f");
List<String> list3 = Arrays.asList("g", "h", "i");

// Chain multiple iterators
Iterator<String> chained = IteratorUtils.chainedIterator(
    list1.iterator(),
    list2.iterator(), 
    list3.iterator()
);

// Iterate through all elements in sequence
while (chained.hasNext()) {
    System.out.println(chained.next()); // a, b, c, d, e, f, g, h, i
}

Filtering Iterators

import org.apache.commons.collections4.Predicate;

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Filter even numbers
Predicate<Integer> evenPredicate = n -> n % 2 == 0;
Iterator<Integer> evenNumbers = IteratorUtils.filteredIterator(numbers.iterator(), evenPredicate);

System.out.println("Even numbers:");
while (evenNumbers.hasNext()) {
    System.out.println(evenNumbers.next()); // 2, 4, 6, 8, 10
}

Transforming Iterators

import org.apache.commons.collections4.Transformer;

List<String> words = Arrays.asList("hello", "world", "java", "collections");

// Transform to uppercase
Transformer<String, String> upperCase = String::toUpperCase;
Iterator<String> upperCaseIterator = IteratorUtils.transformedIterator(words.iterator(), upperCase);

System.out.println("Uppercase words:");
while (upperCaseIterator.hasNext()) {
    System.out.println(upperCaseIterator.next()); // HELLO, WORLD, JAVA, COLLECTIONS
}

// Transform to word lengths
Transformer<String, Integer> lengthTransformer = String::length;
Iterator<Integer> lengthIterator = IteratorUtils.transformedIterator(words.iterator(), lengthTransformer);

Collating Iterator

Merges multiple sorted iterators into a single sorted iterator.

import java.util.Comparator;

List<Integer> list1 = Arrays.asList(1, 4, 7, 10);  // Sorted
List<Integer> list2 = Arrays.asList(2, 5, 8, 11);  // Sorted
List<Integer> list3 = Arrays.asList(3, 6, 9, 12);  // Sorted

// Merge into single sorted sequence
Iterator<Integer> collated = IteratorUtils.collatingIterator(
    Comparator.naturalOrder(),
    list1.iterator(),
    list2.iterator(),
    list3.iterator()
);

System.out.println("Merged sorted sequence:");
while (collated.hasNext()) {
    System.out.println(collated.next()); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
}

Performance Considerations

Trie Performance

// Trie operations are O(k) where k is key length, not collection size
Trie<String, Object> largeTrie = new PatriciaTrie<>();

// Adding 1M entries - each operation is O(key_length)
for (int i = 0; i < 1_000_000; i++) {
    largeTrie.put("key" + i, i);
}

// Prefix search is still O(prefix_length + result_size)
SortedMap<String, Object> results = largeTrie.prefixMap("key123"); // Fast even with 1M entries

Circular Queue Performance

// CircularFifoQueue offers O(1) operations
CircularFifoQueue<String> efficient = new CircularFifoQueue<>(1000);

// All operations are constant time
efficient.offer("item"); // O(1)
String item = efficient.poll(); // O(1)
boolean full = efficient.isFull(); // O(1)

// Much more efficient than removing from front of ArrayList
List<String> inefficient = new ArrayList<>();
// Adding to end: O(1), removing from front: O(n)

Iterator Memory Usage

// Memory-efficient iteration over large collections
List<String> hugeList = generateHugeList(); // Millions of items

// Memory efficient - only holds current position
Iterator<String> memoryEfficient = hugeList.iterator();

// Less memory efficient - may hold references to filtered items
List<String> filtered = hugeList.stream()
    .filter(s -> s.startsWith("prefix"))
    .collect(Collectors.toList());

// Use iterator utilities for memory-efficient processing
Iterator<String> filteredIterator = IteratorUtils.filteredIterator(
    hugeList.iterator(),
    s -> s.startsWith("prefix")
);

Best Practices

Choosing Collection Types

// Use Trie for prefix-based operations
Trie<String, Object> autocomplete = new PatriciaTrie<>(); // Autocomplete, dictionaries

// Use Bloom Filter for membership pre-filtering  
BloomFilter membershipFilter = new SimpleBloomFilter(shape); // Cache layers, deduplication

// Use CircularFifoQueue for fixed-size buffers
CircularFifoQueue<LogEntry> logBuffer = new CircularFifoQueue<>(1000); // Recent items, logs

// Use specialized iterators for complex traversal
Iterator<String> complexTraversal = IteratorUtils.chainedIterator(
    IteratorUtils.filteredIterator(source1.iterator(), predicate1),
    IteratorUtils.transformedIterator(source2.iterator(), transformer)
);

Error Handling

// Safe trie operations
public List<String> safeGetSuggestions(Trie<String, Integer> trie, String prefix) {
    if (prefix == null || trie == null) {
        return Collections.emptyList();
    }
    
    try {
        SortedMap<String, Integer> matches = trie.prefixMap(prefix);
        return new ArrayList<>(matches.keySet());
    } catch (Exception e) {
        // Log error and return empty results
        return Collections.emptyList();
    }
}

// Safe queue operations
public boolean safeOffer(CircularFifoQueue<String> queue, String item) {
    if (queue == null || item == null) {
        return false;
    }
    
    return queue.offer(item); // Always succeeds for CircularFifoQueue
}

Advanced collections in Apache Commons Collections provide specialized data structures for specific performance and functionality requirements. Choose the appropriate type based on your access patterns, memory constraints, and performance needs.

Install with Tessl CLI

npx tessl i tessl/maven-org-apache-commons--commons-collections4

docs

advanced-collections.md

bags.md

bidimaps.md

collection-utilities.md

functional-programming.md

index.md

multimaps.md

tile.json