Логотип Workflow

Article

Functional Interfaces And Lambdas

Topic 11. Functional Interfaces and Lambdas

Functional interfaces and lambdas in Java allow behavior to be passed as values. They complement OOP: domain modeling remains object-oriented, while local behavioral rules are expressed functionally.

Lambda and Functional Interface

Core idea

Before Java 8, simple behavior often required verbose anonymous classes. Lambdas reduced boilerplate and made intent clearer.

A functional interface has a single abstract method (SAM).

@FunctionalInterface
interface MathOp {
    int apply(int a, int b);
}

MathOp add = (a, b) -> a + b;
System.out.println(add.apply(2, 3)); // 5

Where functional style is used in Java

  1. Collections (sort, removeIf, forEach).
  2. Stream API (map, filter, reduce).
  3. Async flows (CompletableFuture).
  4. Callbacks and strategy injection.
  5. Task execution (Runnable, Callable).

Standard functional interfaces

  • Predicate<T>: T -> boolean.
  • Function<T, R>: T -> R.
  • Consumer<T>: T -> void.
  • Supplier<T>: () -> T.
  • UnaryOperator<T>: T -> T.
  • BinaryOperator<T>: (T, T) -> T.
  • BiFunction<T, U, R>: (T, U) -> R.

Example 1. Predicate + Function

Predicate<String> longName = s -> s.length() >= 4;
Function<String, String> upper = String::toUpperCase;

String result = List.of("ann", "alex").stream()
        .filter(longName)
        .map(upper)
        .findFirst()
        .orElse("NONE");

System.out.println(result); // ALEX

Example 2. Consumer + Supplier

Supplier<UUID> idSupplier = UUID::randomUUID;
Consumer<UUID> printer = id -> System.out.println("ID=" + id);

UUID id = idSupplier.get();
printer.accept(id);

Lambda syntax patterns

() -> 42
x -> x * 2
(a, b) -> a + b
(String s) -> s.trim()
(a, b) -> {
    int r = a + b;
    return r;
}

Guideline: shorter lambdas are usually clearer.

Method references

Method references shorten lambdas that only call existing methods.

Forms:

  1. ClassName::staticMethod
  2. obj::instanceMethod
  3. ClassName::instanceMethod
  4. ClassName::new
List<String> names = new ArrayList<>(List.of("Bob", "Ann", "alex"));
names.sort(String::compareToIgnoreCase);
System.out.println(names); // [alex, Ann, Bob]

Closures and effectively final

Lambdas can capture local variables only if they are final or effectively final.

int min = 3;
Predicate<String> p = s -> s.length() >= min;

Invalid:

int min = 3;
min++; // no longer effectively final

This rule avoids confusing lifetime and concurrency behavior.

Function composition

Function<String, String> trim = String::trim;
Function<String, String> upper = String::toUpperCase;
Function<String, String> pipeline = trim.andThen(upper);

System.out.println(pipeline.apply("  java  ")); // JAVA

For predicates:

Predicate<String> notBlank = s -> !s.isBlank();
Predicate<String> shortWord = s -> s.length() <= 5;

Predicate<String> rule = notBlank.and(shortWord);
System.out.println(rule.test("java")); // true

Practical patterns

Strategy injection with lambda

interface DiscountStrategy {
    double apply(double amount);
}

double checkout(double amount, DiscountStrategy strategy) {
    return strategy.apply(amount);
}

double result = checkout(1000, a -> a * 0.9);

Reusable callback wrapper

void withLogging(String opName, Runnable action) {
    long start = System.nanoTime();
    try {
        action.run();
    } finally {
        System.out.println(opName + " took " + (System.nanoTime() - start));
    }
}

Common mistakes

  1. very long lambdas with complex business logic,
  2. side effects hidden inside stream operations,
  3. unclear lambda parameter names in complex contexts,
  4. creating custom functional interfaces when standard ones fit.

When a regular method is better

Extract named methods when:

  1. logic is reused across places,
  2. lambda is too long,
  3. logic needs separate focused tests.

Key takeaway

Functional interfaces and lambdas improve expressiveness when used with discipline: small focused lambdas, clear contracts, minimal side effects.

Quiz

Check what you learned

Please login to pass quizzes.