foreach-ui logo
codeLanguages
account_treeDSA

Quick Actions

quizlock Random Quiz
trending_uplock Progress
  • 1
  • 2
  • 3
  • 4
  • 5
  • quiz
Java
  • Understand what lambda expressions are and why they were introduced
  • Learn the basic syntax of lambda expressions
  • Understand functional interfaces and their relationship with lambdas
  • Know the difference between lambdas and anonymous classes

Introduction to Lambda Expressions

Before Java 8, passing behavior to a method meant creating an anonymous class. Verbose. Intent obscured. Lambda expressions changed everything—treat functionality as a method argument, concise and expressive.

Think of lambdas as shorthand for implementing single-method interfaces.

The Problem Lambda Solves

Sorting a list with a custom comparator before Java 8:

// Before Java 8: Anonymous class (verbose!)
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.compareTo(b);
    }
});

That's 6 lines of code for a simple comparison! Most of it is boilerplate. Now with lambda:

// Java 8+: Lambda expression (concise!)
Collections.sort(names, (a, b) -> a.compareTo(b));

One line, clear intent. The lambda (a, b) -> a.compareTo(b) captures the essence of what we're doing.

What is a Lambda Expression?

A lambda expression is an anonymous function - a block of code that you can pass around. It has:

  • Parameters (can be zero or more)
  • Arrow token (->)
  • Body (expression or block of statements)
// Basic syntax
(parameters) -> expression

// Or with a block body
(parameters) -> { statements; }

Simple Examples

// No parameters
() -> System.out.println("Hello!")

// One parameter (parentheses optional)
x -> x * 2
(x) -> x * 2

// Two parameters
(a, b) -> a + b

// With explicit types
(String s) -> s.length()

// Block body with return
(int a, int b) -> {
    int sum = a + b;
    return sum;
}

Functional Interfaces

Lambda expressions work with functional interfaces - interfaces that have exactly one abstract method. The lambda provides the implementation for that method.

@FunctionalInterface
public interface Runnable {
    void run();  // Single abstract method
}

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);  // Single abstract method
    // (other methods are default or static)
}

The @FunctionalInterface annotation is optional but recommended - it ensures the interface has only one abstract method.

Creating Your Own Functional Interface

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

// Using it with lambdas
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
Calculator max = (a, b) -> Math.max(a, b);

System.out.println(add.calculate(5, 3));       // 8
System.out.println(multiply.calculate(5, 3));  // 15
System.out.println(max.calculate(5, 3));       // 5

Why Lambda Expressions Matter

1. Conciseness

// Without lambda: 4 lines
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Clicked!");
    }
});

// With lambda: 1 line
button.addActionListener(e -> System.out.println("Clicked!"));

2. Readability

The code expresses intent more directly:

// What are we doing? Filtering, mapping, collecting
List<String> result = names.stream()
    .filter(name -> name.startsWith("A"))
    .map(name -> name.toUpperCase())
    .collect(Collectors.toList());

3. Enables Functional Programming

Lambdas enable powerful functional programming patterns:

// Function composition
Function<Integer, Integer> addOne = x -> x + 1;
Function<Integer, Integer> double_ = x -> x * 2;

Function<Integer, Integer> addOneThenDouble = addOne.andThen(double_);
System.out.println(addOneThenDouble.apply(5));  // 12

4. Better API Design

APIs can now accept behavior as parameters:

public void processData(List<String> data, Predicate<String> filter) {
    for (String item : data) {
        if (filter.test(item)) {
            System.out.println(item);
        }
    }
}

// Caller decides the filtering logic
processData(names, name -> name.length() > 5);
processData(names, name -> name.startsWith("J"));

Lambda vs Anonymous Class

Aspect Lambda Anonymous Class
Syntax Concise Verbose
this keyword Refers to enclosing class Refers to anonymous class
Scope Captures effectively final variables Can have its own state
Interfaces Only functional interfaces Any interface/class
Performance Slightly better (no class file) Creates a class file

The this Difference

public class Example {
    private String name = "Outer";
    
    public void demonstrate() {
        // Anonymous class: 'this' refers to the anonymous class
        Runnable anon = new Runnable() {
            private String name = "Inner";
            public void run() {
                System.out.println(this.name);  // "Inner"
            }
        };
        
        // Lambda: 'this' refers to the enclosing class
        Runnable lambda = () -> {
            System.out.println(this.name);  // "Outer"
        };
    }
}

Variable Capture

Lambdas can access variables from their enclosing scope, but those variables must be effectively final (never modified after initialization):

String prefix = "Hello, ";  // Effectively final

// OK: prefix is never modified
Consumer<String> greeter = name -> System.out.println(prefix + name);

// NOT OK: can't modify captured variable
// prefix = "Hi, ";  // Compilation error!

Why this restriction? Lambdas may execute on different threads, and modifying shared variables would cause concurrency issues.

Common Use Cases

Event Handling

button.setOnAction(event -> handleClick());

Collection Operations

list.forEach(item -> System.out.println(item));
list.removeIf(item -> item.isEmpty());
list.sort((a, b) -> a.compareTo(b));

Thread Creation

new Thread(() -> {
    System.out.println("Running in thread");
}).start();

Stream Operations

numbers.stream()
    .filter(n -> n > 0)
    .map(n -> n * 2)
    .forEach(n -> System.out.println(n));

Lambdas revolutionized Java: (params) -> body is anonymous function syntax. Functional interfaces have exactly one abstract method. Use @FunctionalInterface to document them. Lambdas can access effectively final variables. this refers to the enclosing class, not the lambda. They enable functional programming but only work with functional interfaces—not a replacement for all anonymous classes.

© 2026 forEach. All rights reserved.

Privacy Policy•Terms of Service