Lambda Expressions in Java

1. What is a Lambda?

Common examples:
Runnable, Consumer<T>, Predicate<T>, Function<T,R>


2. Basic Syntax

(parameters) -> expression

Example:

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

3. Functional Interface

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

Implement it using a lambda:

Calculator c = (a, b) -> a + b;

System.out.println(c.add(10, 20)); // 30

4. Lambda Syntax

These are equivalent:

Predicate<String> p = (String s) -> {
    return s.length() == 3;
};
Predicate<String> p = s -> s.length() == 3;

Rules:

Example:

Calculator multiply = (a, b) -> {
    int result = a * b;
    return result;
};

For one expression:

Calculator multiply = (a, b) -> a * b;

5. Calling a Lambda

The lambda is executed when the interface method is called.

Predicate<String> p = s -> s.length() > 5;

System.out.println(p.test("Hello World")); // true

6. Common Functional Interfaces

Interface Method Example
Runnable run() () -> System.out.println("Hi")
Consumer<T> accept(T) s -> System.out.println(s)
Predicate<T> test(T) x -> x > 10
Function<T,R> apply(T) x -> x * 2

Example:

Consumer<String> print = s -> System.out.println(s);

print.accept("Hello");

7. Capturing Local Variables

A lambda can use a local variable only if it is final or effectively final.

int number = 10;

Runnable r = () -> System.out.println(number);

This works because number is not changed.

This does not work:

int number = 10;

Runnable r = () -> {
    number++; // ERROR
};

8. @FunctionalInterface

@FunctionalInterface is optional but helps the compiler ensure there is only one abstract method.

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

Adding another abstract method causes a compiler error.


Quick Revision

Concept Key Point
Lambda Short implementation of a functional interface
Introduced Java 8
Requirement One abstract method
Syntax (parameters) -> expression
0 parameters () -> ...
1 parameter x -> ...
Multiple parameters (x, y) -> ...
Multiple statements (x) -> { ... }
Calling Call the interface method
Local variables Final/effectively final
@FunctionalInterface Enforces one abstract method

Simple idea

Instead of creating a separate class or anonymous class:

Predicate<String> isShort = s -> s.length() < 5;

You directly provide the implementation of the interface's single abstract method.