or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-collections.mdbags.mdbidimaps.mdcollection-utilities.mdfunctional-programming.mdindex.mdmultimaps.md

functional-programming.mddocs/

0

# Functional Programming Support

1

2

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.

3

4

## Core Functional Interfaces

5

6

### Predicate<T> Interface

7

8

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

9

10

```java { .api }

11

import org.apache.commons.collections4.Predicate;

12

import org.apache.commons.collections4.PredicateUtils;

13

import org.apache.commons.collections4.CollectionUtils;

14

import java.util.List;

15

import java.util.Arrays;

16

import java.util.Collection;

17

18

// Create custom predicate

19

Predicate<Integer> evenPredicate = n -> n % 2 == 0;

20

Predicate<String> longStringPredicate = s -> s.length() > 5;

21

22

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

23

List<String> words = Arrays.asList("cat", "elephant", "dog", "butterfly", "ant", "hippopotamus");

24

25

// Filter collections using predicates

26

Collection<Integer> evenNumbers = CollectionUtils.select(numbers, evenPredicate);

27

// Result: [2, 4, 6, 8, 10]

28

29

Collection<String> longWords = CollectionUtils.select(words, longStringPredicate);

30

// Result: ["elephant", "butterfly", "hippopotamus"]

31

32

// Test single objects

33

boolean isEven = evenPredicate.evaluate(4); // true

34

boolean isLong = longStringPredicate.evaluate("cat"); // false

35

```

36

37

### Transformer<I, O> Interface

38

39

Transformers convert objects from one type or state to another.

40

41

```java { .api }

42

import org.apache.commons.collections4.Transformer;

43

import org.apache.commons.collections4.TransformerUtils;

44

import java.util.Collection;

45

46

// Simple transformations

47

Transformer<String, String> upperCase = String::toUpperCase;

48

Transformer<String, Integer> stringLength = String::length;

49

Transformer<Integer, String> numberToString = Object::toString;

50

51

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

52

53

// Transform collections

54

Collection<String> upperCaseWords = CollectionUtils.collect(words, upperCase);

55

// Result: ["HELLO", "WORLD", "JAVA", "COLLECTIONS"]

56

57

Collection<Integer> wordLengths = CollectionUtils.collect(words, stringLength);

58

// Result: [5, 5, 4, 11]

59

60

// Transform single objects

61

String upper = upperCase.transform("hello"); // "HELLO"

62

Integer length = stringLength.transform("test"); // 4

63

```

64

65

### Closure<T> Interface

66

67

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

68

69

```java { .api }

70

import org.apache.commons.collections4.Closure;

71

import org.apache.commons.collections4.ClosureUtils;

72

import org.apache.commons.collections4.IterableUtils;

73

74

// Create closures for side effects

75

Closure<String> printClosure = System.out::println;

76

Closure<Integer> squarePrintClosure = n -> System.out.println(n + "² = " + (n * n));

77

78

List<String> messages = Arrays.asList("Hello", "World", "Java");

79

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

80

81

// Apply closure to each element

82

IterableUtils.forEach(messages, printClosure);

83

// Output: Hello, World, Java (each on new line)

84

85

IterableUtils.forEach(numbers, squarePrintClosure);

86

// Output: 1² = 1, 2² = 4, 3² = 9, 4² = 16, 5² = 25

87

88

// Execute closure on single object

89

printClosure.execute("Single message");

90

```

91

92

### Factory<T> Interface

93

94

Factories create new objects on demand.

95

96

```java { .api }

97

import org.apache.commons.collections4.Factory;

98

import org.apache.commons.collections4.FactoryUtils;

99

import org.apache.commons.collections4.map.LazyMap;

100

import java.util.Map;

101

import java.util.HashMap;

102

import java.util.ArrayList;

103

import java.util.List;

104

import java.time.LocalDateTime;

105

106

// Simple factories

107

Factory<String> constantFactory = () -> "default";

108

Factory<List<String>> listFactory = ArrayList::new;

109

Factory<LocalDateTime> timestampFactory = LocalDateTime::now;

110

111

// Use factory to create objects

112

String defaultValue = constantFactory.create(); // "default"

113

List<String> newList = listFactory.create(); // new ArrayList<>()

114

LocalDateTime now = timestampFactory.create(); // current timestamp

115

116

// Lazy map with factory

117

Map<String, List<String>> lazyMap = LazyMap.lazyMap(new HashMap<>(), listFactory);

118

119

// Lists are created on-demand

120

lazyMap.get("key1").add("value1"); // Creates new ArrayList automatically

121

lazyMap.get("key2").add("value2"); // Creates another new ArrayList

122

```

123

124

## Predicate Utilities

125

126

### Built-in Predicates

127

128

```java { .api }

129

import org.apache.commons.collections4.PredicateUtils;

130

131

// Common predicates

132

Predicate<Object> nullPred = PredicateUtils.nullPredicate();

133

Predicate<Object> notNullPred = PredicateUtils.notNullPredicate();

134

Predicate<Object> truePred = PredicateUtils.truePredicate();

135

Predicate<Object> falsePred = PredicateUtils.falsePredicate();

136

137

// Equality predicates

138

Predicate<String> equalToHello = PredicateUtils.equalPredicate("hello");

139

Predicate<Integer> equalToTen = PredicateUtils.equalPredicate(10);

140

141

// Instance type predicate

142

Predicate<Object> stringInstancePred = PredicateUtils.instanceofPredicate(String.class);

143

Predicate<Object> numberInstancePred = PredicateUtils.instanceofPredicate(Number.class);

144

145

// Test objects

146

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

147

148

Collection<Object> notNulls = CollectionUtils.select(mixed, notNullPred);

149

// Result: ["hello", 42, "world", 3.14]

150

151

Collection<Object> strings = CollectionUtils.select(mixed, stringInstancePred);

152

// Result: ["hello", "world"]

153

```

154

155

### Combining Predicates

156

157

```java { .api }

158

// Logical operations

159

Predicate<Integer> positive = n -> n > 0;

160

Predicate<Integer> lessThanTen = n -> n < 10;

161

Predicate<Integer> even = n -> n % 2 == 0;

162

163

// AND combination

164

Predicate<Integer> positiveAndEven = PredicateUtils.andPredicate(positive, even);

165

Predicate<Integer> singleDigitPositive = PredicateUtils.andPredicate(positive, lessThanTen);

166

167

// OR combination

168

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

169

170

// NOT operation

171

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

172

173

// Complex combinations

174

Predicate<Integer> complexPredicate = PredicateUtils.andPredicate(

175

positiveAndEven,

176

lessThanTen

177

); // Positive, even, single-digit numbers

178

179

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

180

181

Collection<Integer> positiveEvenSingleDigit = CollectionUtils.select(numbers, complexPredicate);

182

// Result: [2, 4, 6, 8]

183

```

184

185

### Unique Predicate

186

187

```java { .api }

188

// Only accepts each object once

189

Predicate<String> uniquePred = PredicateUtils.uniquePredicate();

190

191

List<String> withDuplicates = Arrays.asList("a", "b", "a", "c", "b", "d", "a");

192

Collection<String> unique = CollectionUtils.select(withDuplicates, uniquePred);

193

// Result: ["a", "b", "c", "d"] (first occurrence of each)

194

195

// Reset by creating new predicate

196

Predicate<String> anotherUnique = PredicateUtils.uniquePredicate();

197

// This one has fresh state

198

```

199

200

### Invoker Predicate

201

202

```java { .api }

203

// Invoke method and test result

204

Predicate<String> isEmptyPred = PredicateUtils.invokerPredicate("isEmpty");

205

Predicate<List<?>> isListEmptyPred = PredicateUtils.invokerPredicate("isEmpty");

206

207

List<String> testStrings = Arrays.asList("", "hello", "", "world", "");

208

Collection<String> emptyStrings = CollectionUtils.select(testStrings, isEmptyPred);

209

// Result: ["", "", ""]

210

211

// Method with parameters

212

Predicate<String> startsWithHello = PredicateUtils.invokerPredicate(

213

"startsWith",

214

new Class[]{String.class},

215

new Object[]{"hello"}

216

);

217

```

218

219

## Transformer Utilities

220

221

### Built-in Transformers

222

223

```java { .api }

224

import org.apache.commons.collections4.TransformerUtils;

225

226

// Identity transformer (returns input unchanged)

227

Transformer<String, String> identity = TransformerUtils.nopTransformer();

228

229

// Constant transformer (always returns same value)

230

Transformer<Object, String> constant = TransformerUtils.constantTransformer("constant");

231

232

// Null transformer (always returns null)

233

Transformer<Object, Object> nullTransformer = TransformerUtils.nullTransformer();

234

235

// Class transformer (returns object's class)

236

Transformer<Object, Class<?>> classTransformer = TransformerUtils.asTransformer(Object.class);

237

238

// String representation

239

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

240

241

List<Object> objects = Arrays.asList(42, "hello", 3.14, true);

242

Collection<String> strings = CollectionUtils.collect(objects, stringTransformer);

243

// Result: ["42", "hello", "3.14", "true"]

244

245

Collection<Class<?>> classes = CollectionUtils.collect(objects, classTransformer);

246

// Result: [Integer.class, String.class, Double.class, Boolean.class]

247

```

248

249

### Chaining Transformers

250

251

```java { .api }

252

// Chain multiple transformers

253

Transformer<String, String> trim = String::trim;

254

Transformer<String, String> upperCase = String::toUpperCase;

255

Transformer<String, Integer> length = String::length;

256

257

// Chain string operations

258

Transformer<String, String> trimAndUpper = TransformerUtils.chainedTransformer(trim, upperCase);

259

Transformer<String, Integer> trimUpperLength = TransformerUtils.chainedTransformer(

260

trim, upperCase, length

261

);

262

263

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

264

265

Collection<String> cleaned = CollectionUtils.collect(messy, trimAndUpper);

266

// Result: ["HELLO", "WORLD", "JAVA"]

267

268

Collection<Integer> lengths = CollectionUtils.collect(messy, trimUpperLength);

269

// Result: [5, 5, 4]

270

```

271

272

### Map-based Transformer

273

274

```java { .api }

275

// Transform using lookup map

276

Map<String, String> countryToCapital = Map.of(

277

"USA", "Washington D.C.",

278

"France", "Paris",

279

"Japan", "Tokyo",

280

"Germany", "Berlin"

281

);

282

283

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

284

285

List<String> countries = Arrays.asList("USA", "France", "Japan");

286

Collection<String> capitals = CollectionUtils.collect(countries, capitalLookup);

287

// Result: ["Washington D.C.", "Paris", "Tokyo"]

288

```

289

290

### Conditional Transformers

291

292

```java { .api }

293

// If-then-else transformer

294

Predicate<Integer> isPositive = n -> n > 0;

295

Transformer<Integer, String> positiveTransform = n -> "positive: " + n;

296

Transformer<Integer, String> negativeTransform = n -> "negative: " + n;

297

298

Transformer<Integer, String> conditionalTransformer = TransformerUtils.ifTransformer(

299

isPositive,

300

positiveTransform,

301

negativeTransform

302

);

303

304

List<Integer> numbers = Arrays.asList(-5, -1, 0, 1, 5);

305

Collection<String> results = CollectionUtils.collect(numbers, conditionalTransformer);

306

// Result: ["negative: -5", "negative: -1", "negative: 0", "positive: 1", "positive: 5"]

307

308

// Switch transformer with multiple conditions

309

Predicate<Integer> isZero = n -> n == 0;

310

Predicate<Integer> isPositive2 = n -> n > 0;

311

Transformer<Integer, String> zeroTransform = n -> "zero";

312

Transformer<Integer, String> defaultTransform = n -> "unknown";

313

314

Transformer<Integer, String> switchTransformer = TransformerUtils.switchTransformer(

315

new Predicate[]{isZero, isPositive2},

316

new Transformer[]{zeroTransform, positiveTransform},

317

defaultTransform

318

);

319

```

320

321

## Closure Utilities

322

323

### Built-in Closures

324

325

```java { .api }

326

import org.apache.commons.collections4.ClosureUtils;

327

328

// No-operation closure (does nothing)

329

Closure<Object> nopClosure = ClosureUtils.nopClosure();

330

331

// Exception closure (always throws exception)

332

Closure<Object> exceptionClosure = ClosureUtils.exceptionClosure();

333

334

// Invoker closure (calls method on object)

335

Closure<StringBuilder> appendClosure = ClosureUtils.invokerClosure("append",

336

new Class[]{String.class}, new Object[]{" - processed"});

337

338

List<StringBuilder> builders = Arrays.asList(

339

new StringBuilder("item1"),

340

new StringBuilder("item2"),

341

new StringBuilder("item3")

342

);

343

344

IterableUtils.forEach(builders, appendClosure);

345

// Each StringBuilder now has " - processed" appended

346

```

347

348

### Chaining Closures

349

350

```java { .api }

351

// Chain multiple closures

352

Closure<List<String>> addHello = list -> list.add("Hello");

353

Closure<List<String>> addWorld = list -> list.add("World");

354

Closure<List<String>> printSize = list -> System.out.println("Size: " + list.size());

355

356

Closure<List<String>> chainedClosure = ClosureUtils.chainedClosure(

357

addHello, addWorld, printSize

358

);

359

360

List<String> testList = new ArrayList<>();

361

chainedClosure.execute(testList);

362

// testList now contains ["Hello", "World"] and prints "Size: 2"

363

```

364

365

### For and While Closures

366

367

```java { .api }

368

// Execute closure N times

369

Closure<StringBuilder> appendStar = sb -> sb.append("*");

370

Closure<StringBuilder> repeatStar = ClosureUtils.forClosure(5, appendStar);

371

372

StringBuilder sb = new StringBuilder();

373

repeatStar.execute(sb);

374

System.out.println(sb.toString()); // "*****"

375

376

// While closure (execute while condition is true)

377

class Counter {

378

private int count = 0;

379

public int getCount() { return count; }

380

public void increment() { count++; }

381

}

382

383

Counter counter = new Counter();

384

Predicate<Counter> lessThanFive = c -> c.getCount() < 5;

385

Closure<Counter> increment = Counter::increment;

386

387

Closure<Counter> whileClosure = ClosureUtils.whileClosure(lessThanFive, increment);

388

whileClosure.execute(counter);

389

System.out.println(counter.getCount()); // 5

390

```

391

392

## Factory Utilities

393

394

### Built-in Factories

395

396

```java { .api }

397

import org.apache.commons.collections4.FactoryUtils;

398

import java.util.Date;

399

400

// Constant factory

401

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

402

403

// Null factory

404

Factory<Object> nullFactory = FactoryUtils.nullFactory();

405

406

// Exception factory

407

Factory<Object> exceptionFactory = FactoryUtils.exceptionFactory();

408

409

// Prototype factory (clones prototype)

410

List<String> prototype = Arrays.asList("template", "item");

411

Factory<List<String>> prototypeFactory = FactoryUtils.prototypeFactory(prototype);

412

413

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

414

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

415

416

// Instantiate factory (creates new instances via constructor)

417

Factory<Date> dateFactory = FactoryUtils.instantiateFactory(Date.class);

418

Date now1 = dateFactory.create(); // new Date()

419

Date now2 = dateFactory.create(); // another new Date()

420

421

// Instantiate with constructor parameters

422

Factory<StringBuilder> sbFactory = FactoryUtils.instantiateFactory(

423

StringBuilder.class,

424

new Class[]{String.class},

425

new Object[]{"initial"}

426

);

427

StringBuilder sb1 = sbFactory.create(); // new StringBuilder("initial")

428

```

429

430

## Advanced Functional Patterns

431

432

### Pipeline Processing

433

434

```java { .api }

435

public class DataProcessor {

436

// Define processing pipeline with functors

437

private final Predicate<String> validator = s -> s != null && !s.trim().isEmpty();

438

private final Transformer<String, String> cleaner = s -> s.trim().toLowerCase();

439

private final Transformer<String, String> formatter = s -> "processed: " + s;

440

private final Closure<String> logger = s -> System.out.println("Processed: " + s);

441

442

public List<String> processData(List<String> rawData) {

443

return rawData.stream()

444

.filter(validator::evaluate) // Validate

445

.map(cleaner::transform) // Clean

446

.map(formatter::transform) // Format

447

.peek(logger::execute) // Log (side effect)

448

.collect(Collectors.toList());

449

}

450

}

451

```

452

453

### Command Pattern with Closures

454

455

```java { .api }

456

public class CommandProcessor {

457

private final Map<String, Closure<String>> commands = new HashMap<>();

458

459

public CommandProcessor() {

460

// Register commands as closures

461

commands.put("uppercase", String::toUpperCase);

462

commands.put("print", System.out::println);

463

commands.put("reverse", s -> new StringBuilder(s).reverse().toString());

464

}

465

466

public void executeCommand(String commandName, String input) {

467

Closure<String> command = commands.get(commandName);

468

if (command != null) {

469

command.execute(input);

470

}

471

}

472

473

public void registerCommand(String name, Closure<String> command) {

474

commands.put(name, command);

475

}

476

}

477

```

478

479

### Strategy Pattern with Functors

480

481

```java { .api }

482

public class TextProcessor {

483

public enum ProcessingStrategy {

484

UPPERCASE(String::toUpperCase),

485

LOWERCASE(String::toLowerCase),

486

CAPITALIZE(s -> s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase()),

487

REVERSE(s -> new StringBuilder(s).reverse().toString());

488

489

private final Transformer<String, String> transformer;

490

491

ProcessingStrategy(Transformer<String, String> transformer) {

492

this.transformer = transformer;

493

}

494

495

public String process(String input) {

496

return transformer.transform(input);

497

}

498

}

499

500

public List<String> processTexts(List<String> texts, ProcessingStrategy strategy) {

501

return CollectionUtils.collect(texts, strategy.transformer);

502

}

503

}

504

```

505

506

### Functional Validation

507

508

```java { .api }

509

public class ValidationFramework {

510

public static class ValidationResult {

511

private final boolean valid;

512

private final List<String> errors;

513

514

// Constructor and methods...

515

}

516

517

public static <T> ValidationResult validate(T object, Predicate<T>... validators) {

518

List<String> errors = new ArrayList<>();

519

520

for (int i = 0; i < validators.length; i++) {

521

if (!validators[i].evaluate(object)) {

522

errors.add("Validation " + i + " failed");

523

}

524

}

525

526

return new ValidationResult(errors.isEmpty(), errors);

527

}

528

529

// Usage example

530

public ValidationResult validateUser(User user) {

531

return validate(user,

532

u -> u.getName() != null && !u.getName().trim().isEmpty(), // Name required

533

u -> u.getAge() >= 18, // Adult

534

u -> u.getEmail() != null && u.getEmail().contains("@") // Valid email

535

);

536

}

537

}

538

```

539

540

## Performance Considerations

541

542

### Efficient Predicate Composition

543

544

```java { .api }

545

// Efficient: short-circuit evaluation

546

Predicate<String> efficientPredicate = PredicateUtils.andPredicate(

547

s -> s != null, // Fast null check first

548

s -> s.length() > 10, // Then length check

549

s -> s.contains("expensive") // Most expensive check last

550

);

551

552

// Less efficient: expensive operations first

553

Predicate<String> inefficientPredicate = PredicateUtils.andPredicate(

554

s -> expensiveOperation(s), // Expensive operation first

555

s -> s != null // Null check last (may never execute)

556

);

557

```

558

559

### Reusable Functors

560

561

```java { .api }

562

// Create reusable functors to avoid recreation overhead

563

public class CommonFunctors {

564

public static final Predicate<String> NOT_EMPTY =

565

s -> s != null && !s.trim().isEmpty();

566

567

public static final Transformer<String, String> TRIM_UPPERCASE =

568

s -> s == null ? null : s.trim().toUpperCase();

569

570

public static final Factory<List<String>> STRING_LIST_FACTORY =

571

ArrayList::new;

572

573

// Use in multiple contexts

574

public static Collection<String> cleanStrings(Collection<String> input) {

575

return CollectionUtils.collect(

576

CollectionUtils.select(input, NOT_EMPTY),

577

TRIM_UPPERCASE

578

);

579

}

580

}

581

```

582

583

### Memory-Efficient Processing

584

585

```java { .api }

586

// Memory-efficient: process items one at a time

587

public void processLargeDataset(Iterable<String> largeDataset) {

588

Predicate<String> filter = s -> s.startsWith("important");

589

Transformer<String, String> transform = String::toUpperCase;

590

Closure<String> process = this::processItem;

591

592

// Memory-efficient streaming approach

593

for (String item : largeDataset) {

594

if (filter.evaluate(item)) {

595

String transformed = transform.transform(item);

596

process.execute(transformed);

597

}

598

}

599

}

600

601

// Less memory-efficient: creates intermediate collections

602

public void processLargeDatasetInefficient(Collection<String> largeDataset) {

603

Collection<String> filtered = CollectionUtils.select(largeDataset, filter); // Full collection in memory

604

Collection<String> transformed = CollectionUtils.collect(filtered, transform); // Another full collection

605

IterableUtils.forEach(transformed, process); // Process all at once

606

}

607

```

608

609

## Best Practices

610

611

### Type Safety

612

613

```java { .api }

614

// Use specific generic types

615

Predicate<String> stringPredicate = s -> s.length() > 0; // Good

616

Predicate<Object> objectPredicate = o -> o.toString().length() > 0; // Less safe

617

618

// Avoid raw types

619

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

620

```

621

622

### Error Handling

623

624

```java { .api }

625

// Safe predicate that handles nulls

626

Predicate<String> safeStringPredicate = s -> {

627

try {

628

return s != null && s.trim().length() > 0;

629

} catch (Exception e) {

630

return false; // Safe default

631

}

632

};

633

634

// Safe transformer with error handling

635

Transformer<String, Integer> safeParseInt = s -> {

636

try {

637

return s != null ? Integer.parseInt(s.trim()) : 0;

638

} catch (NumberFormatException e) {

639

return 0; // Safe default

640

}

641

};

642

```

643

644

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.