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

functional-programming.mddocs/

Functional Programming Support

Apache Commons Collections provides comprehensive support for functional-style programming through predicates, transformers, closures, and factories. These functional interfaces enable powerful collection processing and manipulation patterns.

Core Functional Interfaces

Predicate<T> Interface

Predicates test objects and return boolean results, used for filtering and validation.

import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.PredicateUtils;
import org.apache.commons.collections4.CollectionUtils;
import java.util.List;
import java.util.Arrays;
import java.util.Collection;

// Create custom predicate
Predicate<Integer> evenPredicate = n -> n % 2 == 0;
Predicate<String> longStringPredicate = s -> s.length() > 5;

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<String> words = Arrays.asList("cat", "elephant", "dog", "butterfly", "ant", "hippopotamus");

// Filter collections using predicates
Collection<Integer> evenNumbers = CollectionUtils.select(numbers, evenPredicate);
// Result: [2, 4, 6, 8, 10]

Collection<String> longWords = CollectionUtils.select(words, longStringPredicate);
// Result: ["elephant", "butterfly", "hippopotamus"]

// Test single objects
boolean isEven = evenPredicate.evaluate(4);     // true
boolean isLong = longStringPredicate.evaluate("cat"); // false

Transformer<I, O> Interface

Transformers convert objects from one type or state to another.

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.TransformerUtils;
import java.util.Collection;

// Simple transformations
Transformer<String, String> upperCase = String::toUpperCase;
Transformer<String, Integer> stringLength = String::length;
Transformer<Integer, String> numberToString = Object::toString;

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

// Transform collections
Collection<String> upperCaseWords = CollectionUtils.collect(words, upperCase);
// Result: ["HELLO", "WORLD", "JAVA", "COLLECTIONS"]

Collection<Integer> wordLengths = CollectionUtils.collect(words, stringLength);
// Result: [5, 5, 4, 11]

// Transform single objects
String upper = upperCase.transform("hello");     // "HELLO"
Integer length = stringLength.transform("test"); // 4

Closure<T> Interface

Closures perform actions on objects without returning values (side effects).

import org.apache.commons.collections4.Closure;
import org.apache.commons.collections4.ClosureUtils;
import org.apache.commons.collections4.IterableUtils;

// Create closures for side effects
Closure<String> printClosure = System.out::println;
Closure<Integer> squarePrintClosure = n -> System.out.println(n + "² = " + (n * n));

List<String> messages = Arrays.asList("Hello", "World", "Java");
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Apply closure to each element
IterableUtils.forEach(messages, printClosure);
// Output: Hello, World, Java (each on new line)

IterableUtils.forEach(numbers, squarePrintClosure);
// Output: 1² = 1, 2² = 4, 3² = 9, 4² = 16, 5² = 25

// Execute closure on single object
printClosure.execute("Single message");

Factory<T> Interface

Factories create new objects on demand.

import org.apache.commons.collections4.Factory;
import org.apache.commons.collections4.FactoryUtils;
import org.apache.commons.collections4.map.LazyMap;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.time.LocalDateTime;

// Simple factories
Factory<String> constantFactory = () -> "default";
Factory<List<String>> listFactory = ArrayList::new;
Factory<LocalDateTime> timestampFactory = LocalDateTime::now;

// Use factory to create objects
String defaultValue = constantFactory.create();        // "default"
List<String> newList = listFactory.create();          // new ArrayList<>()
LocalDateTime now = timestampFactory.create();        // current timestamp

// Lazy map with factory
Map<String, List<String>> lazyMap = LazyMap.lazyMap(new HashMap<>(), listFactory);

// Lists are created on-demand
lazyMap.get("key1").add("value1"); // Creates new ArrayList automatically
lazyMap.get("key2").add("value2"); // Creates another new ArrayList

Predicate Utilities

Built-in Predicates

import org.apache.commons.collections4.PredicateUtils;

// Common predicates
Predicate<Object> nullPred = PredicateUtils.nullPredicate();
Predicate<Object> notNullPred = PredicateUtils.notNullPredicate();
Predicate<Object> truePred = PredicateUtils.truePredicate();
Predicate<Object> falsePred = PredicateUtils.falsePredicate();

// Equality predicates
Predicate<String> equalToHello = PredicateUtils.equalPredicate("hello");
Predicate<Integer> equalToTen = PredicateUtils.equalPredicate(10);

// Instance type predicate
Predicate<Object> stringInstancePred = PredicateUtils.instanceofPredicate(String.class);
Predicate<Object> numberInstancePred = PredicateUtils.instanceofPredicate(Number.class);

// Test objects
List<Object> mixed = Arrays.asList("hello", 42, null, "world", 3.14, null);

Collection<Object> notNulls = CollectionUtils.select(mixed, notNullPred);
// Result: ["hello", 42, "world", 3.14]

Collection<Object> strings = CollectionUtils.select(mixed, stringInstancePred);
// Result: ["hello", "world"]

Combining Predicates

// Logical operations
Predicate<Integer> positive = n -> n > 0;
Predicate<Integer> lessThanTen = n -> n < 10;
Predicate<Integer> even = n -> n % 2 == 0;

// AND combination
Predicate<Integer> positiveAndEven = PredicateUtils.andPredicate(positive, even);
Predicate<Integer> singleDigitPositive = PredicateUtils.andPredicate(positive, lessThanTen);

// OR combination  
Predicate<Integer> positiveOrEven = PredicateUtils.orPredicate(positive, even);

// NOT operation
Predicate<Integer> notEven = PredicateUtils.notPredicate(even); // Odd numbers

// Complex combinations
Predicate<Integer> complexPredicate = PredicateUtils.andPredicate(
    positiveAndEven,
    lessThanTen
); // Positive, even, single-digit numbers

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

Collection<Integer> positiveEvenSingleDigit = CollectionUtils.select(numbers, complexPredicate);
// Result: [2, 4, 6, 8]

Unique Predicate

// Only accepts each object once
Predicate<String> uniquePred = PredicateUtils.uniquePredicate();

List<String> withDuplicates = Arrays.asList("a", "b", "a", "c", "b", "d", "a");
Collection<String> unique = CollectionUtils.select(withDuplicates, uniquePred);
// Result: ["a", "b", "c", "d"] (first occurrence of each)

// Reset by creating new predicate
Predicate<String> anotherUnique = PredicateUtils.uniquePredicate();
// This one has fresh state

Invoker Predicate

// Invoke method and test result
Predicate<String> isEmptyPred = PredicateUtils.invokerPredicate("isEmpty");
Predicate<List<?>> isListEmptyPred = PredicateUtils.invokerPredicate("isEmpty");

List<String> testStrings = Arrays.asList("", "hello", "", "world", "");
Collection<String> emptyStrings = CollectionUtils.select(testStrings, isEmptyPred);
// Result: ["", "", ""]

// Method with parameters
Predicate<String> startsWithHello = PredicateUtils.invokerPredicate(
    "startsWith", 
    new Class[]{String.class}, 
    new Object[]{"hello"}
);

Transformer Utilities

Built-in Transformers

import org.apache.commons.collections4.TransformerUtils;

// Identity transformer (returns input unchanged)
Transformer<String, String> identity = TransformerUtils.nopTransformer();

// Constant transformer (always returns same value)
Transformer<Object, String> constant = TransformerUtils.constantTransformer("constant");

// Null transformer (always returns null)
Transformer<Object, Object> nullTransformer = TransformerUtils.nullTransformer();

// Class transformer (returns object's class)
Transformer<Object, Class<?>> classTransformer = TransformerUtils.asTransformer(Object.class);

// String representation
Transformer<Object, String> stringTransformer = TransformerUtils.stringValueTransformer();

List<Object> objects = Arrays.asList(42, "hello", 3.14, true);
Collection<String> strings = CollectionUtils.collect(objects, stringTransformer);
// Result: ["42", "hello", "3.14", "true"]

Collection<Class<?>> classes = CollectionUtils.collect(objects, classTransformer);
// Result: [Integer.class, String.class, Double.class, Boolean.class]

Chaining Transformers

// Chain multiple transformers
Transformer<String, String> trim = String::trim;
Transformer<String, String> upperCase = String::toUpperCase;
Transformer<String, Integer> length = String::length;

// Chain string operations
Transformer<String, String> trimAndUpper = TransformerUtils.chainedTransformer(trim, upperCase);
Transformer<String, Integer> trimUpperLength = TransformerUtils.chainedTransformer(
    trim, upperCase, length
);

List<String> messy = Arrays.asList("  hello  ", " WORLD ", "   Java   ");

Collection<String> cleaned = CollectionUtils.collect(messy, trimAndUpper);
// Result: ["HELLO", "WORLD", "JAVA"]

Collection<Integer> lengths = CollectionUtils.collect(messy, trimUpperLength);
// Result: [5, 5, 4]

Map-based Transformer

// Transform using lookup map
Map<String, String> countryToCapital = Map.of(
    "USA", "Washington D.C.",
    "France", "Paris",
    "Japan", "Tokyo",
    "Germany", "Berlin"
);

Transformer<String, String> capitalLookup = TransformerUtils.mapTransformer(countryToCapital);

List<String> countries = Arrays.asList("USA", "France", "Japan");
Collection<String> capitals = CollectionUtils.collect(countries, capitalLookup);
// Result: ["Washington D.C.", "Paris", "Tokyo"]

Conditional Transformers

// If-then-else transformer
Predicate<Integer> isPositive = n -> n > 0;
Transformer<Integer, String> positiveTransform = n -> "positive: " + n;
Transformer<Integer, String> negativeTransform = n -> "negative: " + n;

Transformer<Integer, String> conditionalTransformer = TransformerUtils.ifTransformer(
    isPositive,
    positiveTransform,
    negativeTransform
);

List<Integer> numbers = Arrays.asList(-5, -1, 0, 1, 5);
Collection<String> results = CollectionUtils.collect(numbers, conditionalTransformer);
// Result: ["negative: -5", "negative: -1", "negative: 0", "positive: 1", "positive: 5"]

// Switch transformer with multiple conditions
Predicate<Integer> isZero = n -> n == 0;
Predicate<Integer> isPositive2 = n -> n > 0;
Transformer<Integer, String> zeroTransform = n -> "zero";
Transformer<Integer, String> defaultTransform = n -> "unknown";

Transformer<Integer, String> switchTransformer = TransformerUtils.switchTransformer(
    new Predicate[]{isZero, isPositive2},
    new Transformer[]{zeroTransform, positiveTransform},
    defaultTransform
);

Closure Utilities

Built-in Closures

import org.apache.commons.collections4.ClosureUtils;

// No-operation closure (does nothing)
Closure<Object> nopClosure = ClosureUtils.nopClosure();

// Exception closure (always throws exception)
Closure<Object> exceptionClosure = ClosureUtils.exceptionClosure();

// Invoker closure (calls method on object)
Closure<StringBuilder> appendClosure = ClosureUtils.invokerClosure("append", 
    new Class[]{String.class}, new Object[]{" - processed"});

List<StringBuilder> builders = Arrays.asList(
    new StringBuilder("item1"),
    new StringBuilder("item2"),
    new StringBuilder("item3")
);

IterableUtils.forEach(builders, appendClosure);
// Each StringBuilder now has " - processed" appended

Chaining Closures

// Chain multiple closures
Closure<List<String>> addHello = list -> list.add("Hello");
Closure<List<String>> addWorld = list -> list.add("World");
Closure<List<String>> printSize = list -> System.out.println("Size: " + list.size());

Closure<List<String>> chainedClosure = ClosureUtils.chainedClosure(
    addHello, addWorld, printSize
);

List<String> testList = new ArrayList<>();
chainedClosure.execute(testList); 
// testList now contains ["Hello", "World"] and prints "Size: 2"

For and While Closures

// Execute closure N times
Closure<StringBuilder> appendStar = sb -> sb.append("*");
Closure<StringBuilder> repeatStar = ClosureUtils.forClosure(5, appendStar);

StringBuilder sb = new StringBuilder();
repeatStar.execute(sb);
System.out.println(sb.toString()); // "*****"

// While closure (execute while condition is true)
class Counter {
    private int count = 0;
    public int getCount() { return count; }
    public void increment() { count++; }
}

Counter counter = new Counter();
Predicate<Counter> lessThanFive = c -> c.getCount() < 5;
Closure<Counter> increment = Counter::increment;

Closure<Counter> whileClosure = ClosureUtils.whileClosure(lessThanFive, increment);
whileClosure.execute(counter);
System.out.println(counter.getCount()); // 5

Factory Utilities

Built-in Factories

import org.apache.commons.collections4.FactoryUtils;
import java.util.Date;

// Constant factory
Factory<String> constantStringFactory = FactoryUtils.constantFactory("default");

// Null factory  
Factory<Object> nullFactory = FactoryUtils.nullFactory();

// Exception factory
Factory<Object> exceptionFactory = FactoryUtils.exceptionFactory();

// Prototype factory (clones prototype)
List<String> prototype = Arrays.asList("template", "item");
Factory<List<String>> prototypeFactory = FactoryUtils.prototypeFactory(prototype);

List<String> copy1 = prototypeFactory.create(); // Independent copy
List<String> copy2 = prototypeFactory.create(); // Another independent copy

// Instantiate factory (creates new instances via constructor)
Factory<Date> dateFactory = FactoryUtils.instantiateFactory(Date.class);
Date now1 = dateFactory.create(); // new Date()
Date now2 = dateFactory.create(); // another new Date()

// Instantiate with constructor parameters
Factory<StringBuilder> sbFactory = FactoryUtils.instantiateFactory(
    StringBuilder.class,
    new Class[]{String.class},
    new Object[]{"initial"}
);
StringBuilder sb1 = sbFactory.create(); // new StringBuilder("initial")

Advanced Functional Patterns

Pipeline Processing

public class DataProcessor {
    // Define processing pipeline with functors
    private final Predicate<String> validator = s -> s != null && !s.trim().isEmpty();
    private final Transformer<String, String> cleaner = s -> s.trim().toLowerCase();
    private final Transformer<String, String> formatter = s -> "processed: " + s;
    private final Closure<String> logger = s -> System.out.println("Processed: " + s);
    
    public List<String> processData(List<String> rawData) {
        return rawData.stream()
            .filter(validator::evaluate)                    // Validate
            .map(cleaner::transform)                        // Clean
            .map(formatter::transform)                      // Format
            .peek(logger::execute)                          // Log (side effect)
            .collect(Collectors.toList());
    }
}

Command Pattern with Closures

public class CommandProcessor {
    private final Map<String, Closure<String>> commands = new HashMap<>();
    
    public CommandProcessor() {
        // Register commands as closures
        commands.put("uppercase", String::toUpperCase);
        commands.put("print", System.out::println);
        commands.put("reverse", s -> new StringBuilder(s).reverse().toString());
    }
    
    public void executeCommand(String commandName, String input) {
        Closure<String> command = commands.get(commandName);
        if (command != null) {
            command.execute(input);
        }
    }
    
    public void registerCommand(String name, Closure<String> command) {
        commands.put(name, command);
    }
}

Strategy Pattern with Functors

public class TextProcessor {
    public enum ProcessingStrategy {
        UPPERCASE(String::toUpperCase),
        LOWERCASE(String::toLowerCase),
        CAPITALIZE(s -> s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase()),
        REVERSE(s -> new StringBuilder(s).reverse().toString());
        
        private final Transformer<String, String> transformer;
        
        ProcessingStrategy(Transformer<String, String> transformer) {
            this.transformer = transformer;
        }
        
        public String process(String input) {
            return transformer.transform(input);
        }
    }
    
    public List<String> processTexts(List<String> texts, ProcessingStrategy strategy) {
        return CollectionUtils.collect(texts, strategy.transformer);
    }
}

Functional Validation

public class ValidationFramework {
    public static class ValidationResult {
        private final boolean valid;
        private final List<String> errors;
        
        // Constructor and methods...
    }
    
    public static <T> ValidationResult validate(T object, Predicate<T>... validators) {
        List<String> errors = new ArrayList<>();
        
        for (int i = 0; i < validators.length; i++) {
            if (!validators[i].evaluate(object)) {
                errors.add("Validation " + i + " failed");
            }
        }
        
        return new ValidationResult(errors.isEmpty(), errors);
    }
    
    // Usage example
    public ValidationResult validateUser(User user) {
        return validate(user,
            u -> u.getName() != null && !u.getName().trim().isEmpty(),  // Name required
            u -> u.getAge() >= 18,                                      // Adult
            u -> u.getEmail() != null && u.getEmail().contains("@")     // Valid email
        );
    }
}

Performance Considerations

Efficient Predicate Composition

// Efficient: short-circuit evaluation
Predicate<String> efficientPredicate = PredicateUtils.andPredicate(
    s -> s != null,                    // Fast null check first
    s -> s.length() > 10,             // Then length check
    s -> s.contains("expensive")       // Most expensive check last
);

// Less efficient: expensive operations first
Predicate<String> inefficientPredicate = PredicateUtils.andPredicate(
    s -> expensiveOperation(s),        // Expensive operation first
    s -> s != null                     // Null check last (may never execute)
);

Reusable Functors

// Create reusable functors to avoid recreation overhead
public class CommonFunctors {
    public static final Predicate<String> NOT_EMPTY = 
        s -> s != null && !s.trim().isEmpty();
    
    public static final Transformer<String, String> TRIM_UPPERCASE = 
        s -> s == null ? null : s.trim().toUpperCase();
    
    public static final Factory<List<String>> STRING_LIST_FACTORY = 
        ArrayList::new;
    
    // Use in multiple contexts
    public static Collection<String> cleanStrings(Collection<String> input) {
        return CollectionUtils.collect(
            CollectionUtils.select(input, NOT_EMPTY),
            TRIM_UPPERCASE
        );
    }
}

Memory-Efficient Processing

// Memory-efficient: process items one at a time
public void processLargeDataset(Iterable<String> largeDataset) {
    Predicate<String> filter = s -> s.startsWith("important");
    Transformer<String, String> transform = String::toUpperCase;
    Closure<String> process = this::processItem;
    
    // Memory-efficient streaming approach
    for (String item : largeDataset) {
        if (filter.evaluate(item)) {
            String transformed = transform.transform(item);
            process.execute(transformed);
        }
    }
}

// Less memory-efficient: creates intermediate collections
public void processLargeDatasetInefficient(Collection<String> largeDataset) {
    Collection<String> filtered = CollectionUtils.select(largeDataset, filter);    // Full collection in memory
    Collection<String> transformed = CollectionUtils.collect(filtered, transform); // Another full collection
    IterableUtils.forEach(transformed, process);                                   // Process all at once
}

Best Practices

Type Safety

// Use specific generic types
Predicate<String> stringPredicate = s -> s.length() > 0;           // Good
Predicate<Object> objectPredicate = o -> o.toString().length() > 0; // Less safe

// Avoid raw types
Predicate rawPredicate = s -> true; // Don't do this

Error Handling

// Safe predicate that handles nulls
Predicate<String> safeStringPredicate = s -> {
    try {
        return s != null && s.trim().length() > 0;
    } catch (Exception e) {
        return false; // Safe default
    }
};

// Safe transformer with error handling  
Transformer<String, Integer> safeParseInt = s -> {
    try {
        return s != null ? Integer.parseInt(s.trim()) : 0;
    } catch (NumberFormatException e) {
        return 0; // Safe default
    }
};

Functional programming support in Apache Commons Collections enables powerful, composable operations on collections while maintaining type safety and performance. Use these patterns to create clean, reusable, and maintainable code.

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