Skip to content

30 · 32 · 5 min

Ideas worth borrowing

Modern object oriented languages have absorbed a lot from functional programming. The point is not to stop using objects; it is that a few ideas remove specific classes of bug.

Pure functions

Same input, same output, no side effects.

java
int total(List<Item> items) {           // pure
    return items.stream().mapToInt(Item::price).sum();
}

void applyDiscount() {                  // not pure: reads and writes state
    this.total = this.total * 0.9;
}

A pure function is testable with no setup, safe to call from any thread, safe to cache, and comprehensible without reading anything else. Pushing logic into pure functions and keeping the state changes thin at the edges is most of the practical benefit.

Functions as values

java
List<String> names = people.stream()
    .filter(p -> p.age() >= 18)
    .map(Person::name)
    .sorted()
    .toList();

The loop said how. This says what. It is also harder to get an index wrong in, because there are no indices.

map, filter, reduce

OperationDoes
maptransform each element
filterkeep the ones matching
reducecombine into one value

Nearly every loop that builds a list is one of these three, and naming which one it is makes the intent visible.

Where it replaces a pattern

The strategy pattern in a classical form is an interface, several implementing classes and a field. With functions as values it is a parameter:

java
// before: an interface and a class per strategy
sorter.sort(items, new ByPriceComparator());

// after
items.sort(Comparator.comparingInt(Item::price));

Several of the classic patterns are similarly shorter in a language with first class functions, which is worth knowing when someone asks why patterns feel less prominent than they did.

Where it is worse

Streams have overhead, and a tight numeric loop is faster written plainly. Debugging a long chain is harder than stepping through statements. And a chain of six operations with a lambda on each is not more readable than a loop just because it is functional.

The honest rule: use it where it makes the intent clearer, not everywhere.

Immutability is the common thread

These ideas work because values do not change underneath you. That is the same argument as the immutability page, arriving from a different direction, and it is why the two topics reinforce each other.