Skip to content

From a filter class to a lambda

โ˜• Java 17 ยท Passing Behavior Around with Lambdas ยท 1/3

Thinking in functions

Object style Functional style
build objects, change their state describe the result you want
write the loop step by step pass small rules, let other code loop
focus on how focus on what

Java stays object-oriented: functional programming is an extra tool on top. Its key piece is the lambda: a block of code with parameters and a body, but no name, that you can pass to a method.

The scenario: filtering a catalog

public record Movie(String title, boolean isNew, boolean isKidFriendly) { }

public interface MovieFilter {
    boolean test(Movie movie);
}

MovieFilter asks one question about a movie and answers with a boolean. A method can print every movie that passes any filter:

static void print(List<Movie> catalog, MovieFilter filter) {
    for (Movie movie : catalog)
        if (filter.test(movie))
            System.out.print(movie.title() + " ");
    System.out.println();
}

print() is nicely generic: it doesn't know which rule it applies.

The old way: one class per rule

public class KidFriendlyFilter implements MovieFilter {
    public boolean test(Movie m) {
        return m.isKidFriendly();
    }
}

print(catalog, new KidFriendlyFilter());

A new file and a new class for a single expression. Every new rule means another class.

The new way: one line per rule

print(catalog, m -> m.isNew());              // new releases
print(catalog, m -> m.isKidFriendly());      // kid-friendly titles
print(catalog, m -> !m.isKidFriendly());     // everything not for kids

m -> m.isNew() reads as given a movie m, keep it if it's new. print() didn't change: it still expects a MovieFilter, and Java turns the lambda into one.

Code now, run later

  1. You write the lambda. print(catalog, m -> m.isNew()); checks no movie yet: it hands code to print().
  2. Java matches it to the interface. print() expects a MovieFilter, whose only abstract method is boolean test(Movie movie). So m is a Movie and the body must produce a boolean.
  3. print() runs it later, once per movie, when it calls filter.test(movie).

A lambda always needs a context that tells Java what it is: here, the MovieFilter parameter. That context is called the target type.

Lambdas can be written in several forms, from long to very short. The next page goes through every rule.

๐Ÿ’ป Code: Java17_Part_8_Functional_Programming on GitHub

Next: lambda syntax โ†’