Article start
Java Programming: From Zero to Enterprise
4. Advanced Java & Frameworks

32. Lambda Expressions & Functional Interfaces

Passing behavior as arguments elegantly without massive boilerplate classes.

February 22, 2026·68

[!NOTE] Introduced in Java 8, Lambda Expressions fundamentally modernized the language. They allow you to pass specific "behavior" (a function) into another function, without having to build a massive, verbose Anonymous Inner Class.

The Boilerplate Problem

Imagine you have a Button object in a UI. You want to tell the button: "When you are clicked, execute this specific block of code."

Historically, you had to physically create a brand new class that implemented the ClickListener interface, write the overriding method, instantiate it, and pass it in.

// 2004 Java (Pre-Java 8)
button.setOnClickListener(new ClickListener() {
    @Override
    public void onClick() {
         System.out.println("Button clicked!");
    }
});

The Lambda Solution

A Lambda expression condenses all of that into a single, elegant arrow function: parameter -> expression.

If the interface only has one abstract method (called a Functional Interface), the Java compiler is smart enough to just inject your arrow function directly into that slot!

// Modern Java 8+ Implementation!
button.setOnClickListener( () -> System.out.println("Button Clicked!") );

Anatomy of a Lambda

Lambdas can take parameters and can have multi-line bodies wrapped in curly braces.

  1. No parameters:

() -> System.out.println("No args");

  1. One parameter (parentheses are optional!):

name -> System.out.println("Hello " + name);

  1. Multiple parameters with a multi-line body (requires { } and 'return'):

(x, y) -> {
    int sum = x + y;
    return sum;
}

Practical Use: Processing ArrayLists

Lambdas shine brightest when interacting with Collections.

import java.util.ArrayList;

public class Main {
  public static void main(String[] args) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();
    numbers.add(5);
    numbers.add(9);
    numbers.add(8);
    numbers.add(1);
    
    // Instead of writing a complex Iterator while-loop...
    // We pass a Lambda function that tells '.forEach()' exactly what to do with each element 'n'!
    numbers.forEach( (n) -> { System.out.println(n); } );
  }
}

[!TIP] You cannot use a lambda expression if the target interface has two or more abstract methods. Lambdas ONLY work on Functional Interfaces (like Runnable, Callable, or Comparator) because otherwise the compiler wouldn't know which method you are trying to override!

Lambdas Work Best With Clear Intent

A lambda is a compact way to pass behavior, but compact code is not always clearer. Use lambdas for small, obvious behavior. If the logic grows, move it into a named method.

Comparator Example

List<String> names = new ArrayList<>();
names.add("Ravi");
names.add("Asha");
names.add("Meera");

names.sort((a, b) -> a.compareToIgnoreCase(b));

Method Reference

names.forEach(System.out::println);

A method reference is often cleaner when the lambda only forwards its input to an existing method.

Common Functional Interfaces

InterfaceShapeTypical use
Predicate<T>T to booleanFiltering
Function<T, R>T to RMapping
Consumer<T>T to voidPerforming an action
Supplier<T>No input to TCreating values lazily

Mini Practice

Create a list of marks. Use removeIf with a lambda to remove failed marks, then sort the remaining marks in descending order.

Practice Lab: Sort and Filter With Lambdas

Use small lambda expressions to make collection operations more expressive.

  1. Create an ArrayList<String> of names.
  2. Remove names shorter than four characters using removeIf.
  3. Sort names case-insensitively with a lambda comparator.
  4. Print each name with forEach.
  5. Replace a simple lambda with a method reference where possible.

Goal: Practice lambdas as behavior passed into collection methods.

Revision Checkpoint

  • Lambda: Compact way to pass behavior.
  • Functional interface: Interface with one abstract method.
  • Arrow: Java uses ->.
  • Method reference: Shorter syntax when forwarding to an existing method.
  • Keep it small: Move complex lambda logic into named methods.

Before the quiz: Identify the functional interface behind a lambda example.