Script Valley
Java: Complete Language Course
Modern Java Features and Best PracticesLesson 6.1

Java lambda expressions and functional interfaces

lambda syntax, functional interface, @FunctionalInterface, Predicate, Function, Consumer, Supplier, BiFunction, method references, type inference

Lambda Expressions

Lambdas are concise anonymous functions. They implement functional interfaces — interfaces with exactly one abstract method — inline without declaring a full class.

Syntax Evolution

// Full anonymous class
Comparator c1 = new Comparator() {
    @Override
    public int compare(String a, String b) { return a.compareTo(b); }
};

// Lambda with explicit types
Comparator c2 = (String a, String b) -> a.compareTo(b);

// Lambda with inferred types (preferred)
Comparator c3 = (a, b) -> a.compareTo(b);

// Method reference (most concise when delegating to existing method)
Comparator c4 = String::compareTo;

Built-in Functional Interfaces

Predicate isEven    = n -> n % 2 == 0;
Function len = String::length;
Consumer print        = System.out::println;
Supplier> fresh  = ArrayList::new;

System.out.println(isEven.test(4));       // true
System.out.println(len.apply("hello"));  // 5
print.accept("Lambda!");                  // Lambda!
List list = fresh.get();

Lambdas can capture local variables that are effectively final — never reassigned after initialization. A variable does not need the final keyword; it just must not be modified. Trying to capture a mutated variable is a compile error.

Use method references when the lambda body only calls a single existing method that matches the functional interface's signature. They reduce noise and make the intent immediately clear.

Compose predicates using and(), or(), and negate() built into Predicate: isEven.and(n -> n > 10) returns a new Predicate that checks both conditions. This avoids nested lambdas and keeps each condition independently testable.

Up next

Java Optional — avoiding NullPointerException properly

Sign in to track progress