Card 05/ 09

ExampleDifficulty: Advanced1 min

Functional Interfaces Example: All Four Shapes in a File-Reading Pipeline

Filtered, converted and printed, and none of the four steps is a comparator.

The same four interfaces appear as the steps of a stream pipeline, a chain of operations over a sequence of values. A file of invoice lines, filtered, converted and printed, with each step's lambda, the inline function it runs, named by its interface:

java
Supplier<List<Invoice>> empty = ArrayList::new;
Predicate<String> notBlank = line -> !line.isBlank();
Function<String, Invoice> parse = Invoice::parse;
Consumer<Invoice> print = System.out::println;

List<Invoice> invoices = Files.lines(path)
        .filter(notBlank)
        .map(parse)
        .collect(Collectors.toCollection(empty));

invoices.forEach(print);

filter wants something that answers yes or no about one element. map wants something that turns one thing into another. forEach wants something that takes an element and produces nothing. toCollection wants something that produces a collection from nothing.

Put this beside invoices.sort((a, b) -> ...), where the same kind of lambda became a Comparator, and the shared fact comes out: in both, the lambda's type came from the parameter it was passed to, and nothing in the lambda itself said what it was. A comparator, a predicate and a function look identical on the page; the method they are handed to is what decides.