Card 05/ 09

ExampleDifficulty: Advanced1 min

The Same Four Shapes in a Pipeline That Reads a File

A file of invoice lines, filtered, converted and printed. Each step takes one of the four shapes, and none of them is called a comparator.

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 the one-line 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.