# Lambda Expressions

Course: [Java](https://www.devtutorials.ai/learn/java) · Section: Functional Programming
Source: https://www.devtutorials.ai/learn/java/functional-programming/lambda-expressions

> Write short, nameless functions with lambdas, use them with functional interfaces like Predicate, Function, Consumer and Supplier, and shorten them with method references.

Think about leaving a note for a friend who is minding your shop.

You could write a whole letter: "Dear Ravi, I hope you are well. When a customer comes in, please check whether they are a member. If they are, give them ten percent off. Thank you, Asha."

Or you could stick a short note on the till: "Member → 10% off."

Both say the same thing. The short note is quicker to write and quicker to read.

A lambda expression is that short note. It lets you hand a small piece of behaviour to a method, in one line, without writing a whole class.

In simple words: a lambda is a short, nameless method that you can pass around like a value.

## What You Will Learn

In this lesson, you will learn:

1. What lambda expressions are, and why Java added them.
2. How lambdas and functional interfaces work together.
3. The lambda syntax, with and without parameters.
4. How lambdas return values.
5. The four most used built-in functional interfaces: `Predicate`, `Function`, `Consumer` and `Supplier`.
6. How method references make lambdas even shorter.
7. How lambdas compare with anonymous classes.

## Start With a Working Example

Press **Run**.

```java runnable title="One line of behaviour, passed into a method"
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> marks = new ArrayList<>(List.of(72, 35, 88, 28, 64));

        marks.removeIf(m -> m < 40);
        System.out.println("Passing marks: " + marks);

        marks.forEach(m -> System.out.println("Mark: " + m));

        marks.sort((a, b) -> b - a);
        System.out.println("Highest first: " + marks);
    }
}
```

Expected output:

```text
Passing marks: [72, 88, 64]
Mark: 72
Mark: 88
Mark: 64
Highest first: [88, 72, 64]
```

Each `->` is a lambda. `m -> m < 40` is a rule that says which marks to remove. `(a, b) -> b - a` is a rule that says how to compare two marks.

The methods `removeIf`, `forEach` and `sort` do the looping. The lambdas only say **what** to do with each item.

### Try This

Change `m < 40` to `m < 70`. Only one line changes, and now only `72` and `88` remain.

## Introduction to Lambda Expressions

### What are Lambda Expressions?

A **lambda expression** is a short block of code that takes parameters and produces a result, but has **no name** and does not belong to any class.

```text
(parameters) -> body
```

- On the left of the arrow are the **parameters**, the values it receives.
- On the right is the **body**, the work it does.
- The arrow `->` separates the two. Read it as "goes to" or "becomes".

So `x -> x * 2` reads as "x becomes x times two".

You can store a lambda in a variable, pass it to a method, or return it from a method. That is what makes it powerful: **behaviour becomes a value**.

### Why Lambda Expressions Were Introduced

Before Java 8 (2014), passing behaviour to a method meant writing an **anonymous class**. Even a one-line rule needed five or six lines of setup code.

Lambdas were added in Java 8 to:

- **cut repeated code**, so a simple rule takes one line;
- **make code easier to read**, because the important part is not buried;
- **support streams**, a powerful way to process collections, which you will learn in the next lesson;
- **support parallel work**, because behaviour can be handed to many threads.

```java runnable title="The same rule, the old way and the lambda way"
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(List.of("Meena", "Ravi", "Arjun", "Asha"));

        names.sort(new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                return a.length() - b.length();
            }
        });
        System.out.println("Old way: " + names);

        names.sort((a, b) -> b.length() - a.length());
        System.out.println("Lambda:  " + names);
    }
}
```

Expected output:

```text
Old way: [Ravi, Asha, Meena, Arjun]
Lambda:  [Meena, Arjun, Ravi, Asha]
```

The old way needed six lines to say "compare by length". The lambda says it in one.

## Functional Interfaces

A lambda cannot float around on its own. It always fills in a **functional interface**.

A **functional interface** is an interface with **exactly one** abstract method. You met them in the Interfaces lesson.

The lambda becomes the body of that one method. Java can tell which method it is, because there is only one.

```text
@FunctionalInterface
interface Greeter {
    String greet(String name);   // the one abstract method
}

Greeter hello = name -> "Hello, " + name;   // the lambda is greet's body
```

The type of the variable, `Greeter`, tells Java what the lambda must look like: one `String` in, one `String` out.

`@FunctionalInterface` is optional. It asks the compiler to check there is exactly one abstract method. If someone adds a second one later, the code stops compiling, which protects every lambda that uses it.

```java runnable title="Your own functional interface, filled in by lambdas"
public class Main {
    public static void main(String[] args) {
        Discount festival = price -> price * 80 / 100;
        Discount flatFifty = price -> price - 50;
        Discount none = price -> price;

        int price = 1000;
        System.out.println("Festival: " + festival.apply(price));
        System.out.println("Flat 50 off: " + flatFifty.apply(price));
        System.out.println("No discount: " + none.apply(price));
    }
}

@FunctionalInterface
interface Discount {
    int apply(int price);
}
```

Expected output:

```text
Festival: 800
Flat 50 off: 950
No discount: 1000
```

Each lambda is a different `Discount`. Calling `apply` runs that lambda's body.

A functional interface can still have `default` and `static` methods. Only the **abstract** methods are counted, and there must be exactly one.

## Lambda Syntax

A lambda has a few forms. Java lets you leave out parts when they are obvious.

| Form | Example | When to use it |
|---|---|---|
| No parameters | `() -> "Hello"` | The method takes nothing |
| One parameter | `name -> name.length()` | Brackets are optional with exactly one parameter |
| Several parameters | `(a, b) -> a + b` | Brackets are required |
| Typed parameters | `(int a, int b) -> a + b` | Types are usually left out, because Java works them out |
| Block body | `x -> { int y = x * 2; return y + 1; }` | More than one statement |

Rules to remember:

- With **one** parameter and no type, you can leave out the brackets: `x -> x * 2`.
- With **zero** or **several** parameters, the brackets are required: `() -> 5`, `(a, b) -> a * b`.
- A **one-line** body needs no braces and no `return`.
- A body in **braces** `{ }` needs a `return` if it gives back a value, and `;` after each statement.

## Lambda with Parameters

A lambda's parameters work like a method's parameters. Their types come from the functional interface.

```java runnable title="Zero, one and two parameters"
public class Main {
    public static void main(String[] args) {
        Greeting welcome = () -> System.out.println("Welcome to the store!");
        welcome.say();

        Shouter loud = text -> System.out.println(text.toUpperCase() + "!");
        loud.shout("big sale today");

        Adder add = (a, b) -> a + b;
        System.out.println("12 + 30 = " + add.sum(12, 30));
    }
}

interface Greeting {
    void say();
}

interface Shouter {
    void shout(String text);
}

interface Adder {
    int sum(int a, int b);
}
```

Expected output:

```text
Welcome to the store!
BIG SALE TODAY!
12 + 30 = 42
```

`welcome` has no parameters, so it starts with empty brackets `()`. `loud` has one, so it needs no brackets. `add` has two, so they are in brackets.

Java worked out that `text` is a `String`, and `a` and `b` are `int`, from the interfaces.

### Using Variables From Outside

A lambda can use variables from the code around it, but only if they never change after being set. Java calls these **effectively final**.

```text
int bonus = 5;
Adder withBonus = (a, b) -> a + b + bonus;   // fine
bonus = 10;                                   // now the lambda line will not compile
```

Lambda parameters cannot reuse the name of a local variable that is already in scope. If `name` is already a variable in the method, `name -> name.length()` does not compile. Pick a different parameter name, like `n`.

## Lambda with Return Values

When a lambda's body is a **single expression**, its value is returned automatically. You do not write `return`.

When the body needs **several statements**, put them in braces and use `return`.

```java runnable title="Expression body vs block body"
public class Main {
    public static void main(String[] args) {
        Calculator square = n -> n * n;

        Calculator tax = amount -> {
            int rate = amount > 1000 ? 18 : 5;
            int taxDue = amount * rate / 100;
            return amount + taxDue;
        };

        Checker isAdult = age -> age >= 18;

        System.out.println("Square of 9: " + square.calc(9));
        System.out.println("Price with tax (500): " + tax.calc(500));
        System.out.println("Price with tax (2000): " + tax.calc(2000));
        System.out.println("Is 16 an adult? " + isAdult.check(16));
    }
}

interface Calculator {
    int calc(int value);
}

interface Checker {
    boolean check(int value);
}
```

Expected output:

```text
Square of 9: 81
Price with tax (500): 525
Price with tax (2000): 2360
Is 16 an adult? false
```

`n -> n * n` returns `n * n` automatically. The `tax` lambda has three statements, so it uses braces and an explicit `return`.

`age -> age >= 18` returns a `boolean`, because a comparison is true or false.

## Built-in Functional Interfaces

You do not need to write your own interface for every lambda. Java provides many ready-made ones in **`java.util.function`**. Four of them cover most needs.

| Interface | Method | Takes | Returns | Think of it as |
|---|---|---|---|---|
| `Predicate<T>` | `test(T)` | One value | `boolean` | A yes/no question |
| `Function<T, R>` | `apply(T)` | One value | A value | A converter |
| `Consumer<T>` | `accept(T)` | One value | Nothing | A doer |
| `Supplier<T>` | `get()` | Nothing | A value | A maker |

### Predicate

A **`Predicate<T>`** takes a value and answers **true or false**. Use it for checks and filters.

Predicates can be combined with `and`, `or` and `negate`.

### Function

A **`Function<T, R>`** takes a value of type `T` and returns a value of type `R`. Use it to convert one thing into another.

Functions can be chained with `andThen`.

### Consumer

A **`Consumer<T>`** takes a value and **returns nothing**. It just does something with it, like printing or saving.

### Supplier

A **`Supplier<T>`** takes **nothing** and returns a value. Use it to create or fetch something on demand.

```java runnable title="Predicate, Function, Consumer and Supplier"
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        Predicate<Integer> isEven = n -> n % 2 == 0;
        Predicate<Integer> isBig = n -> n > 100;
        System.out.println("Is 42 even? " + isEven.test(42));
        System.out.println("Is 42 even AND big? " + isEven.and(isBig).test(42));
        System.out.println("Is 7 NOT even? " + isEven.negate().test(7));

        Function<String, Integer> length = text -> text.length();
        Function<Integer, Integer> doubled = n -> n * 2;
        System.out.println("Length of 'Chennai': " + length.apply("Chennai"));
        System.out.println("Length, then doubled: " + length.andThen(doubled).apply("Chennai"));

        Consumer<String> welcome = name -> System.out.println("Welcome, " + name + "!");
        welcome.accept("Asha");

        Supplier<String> defaultCity = () -> "Bengaluru";
        System.out.println("Default city: " + defaultCity.get());
    }
}
```

Expected output:

```text
Is 42 even? true
Is 42 even AND big? false
Is 7 NOT even? true
Length of 'Chennai': 7
Length, then doubled: 14
Welcome, Asha!
Default city: Bengaluru
```

`isEven.and(isBig)` builds a new predicate from two others. `length.andThen(doubled)` runs `length` first, then feeds its answer to `doubled`.

### Two-Argument Versions

Some interfaces have a version that takes **two** inputs:

| Interface | Takes | Returns | Example |
|---|---|---|---|
| `BiFunction<T, U, R>` | Two values | A value | `(price, qty) -> price * qty` |
| `BiPredicate<T, U>` | Two values | `boolean` | `(a, b) -> a.equals(b)` |
| `BiConsumer<T, U>` | Two values | Nothing | `(key, value) -> System.out.println(key + "=" + value)` |
| `UnaryOperator<T>` | One value | Same type | `s -> s.trim()` |
| `BinaryOperator<T>` | Two values of the same type | Same type | `(a, b) -> a + b` |

```java runnable title="Pass a Predicate into your own method"
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        List<Integer> prices = List.of(120, 850, 45, 1500, 300);

        System.out.println("Under 200: " + count(prices, p -> p < 200));
        System.out.println("Over 500: " + count(prices, p -> p > 500));
        System.out.println("Even: " + count(prices, p -> p % 2 == 0));

        BiFunction<Integer, Integer, Integer> lineTotal = (price, qty) -> price * qty;
        System.out.println("3 items at 45: " + lineTotal.apply(45, 3));
    }

    static int count(List<Integer> values, Predicate<Integer> rule) {
        int total = 0;
        for (int v : values) {
            if (rule.test(v)) {
                total++;
            }
        }
        return total;
    }
}
```

Expected output:

```text
Under 200: 2
Over 500: 2
Even: 4
3 items at 45: 135
```

`count` is written once. Each call passes a different rule as a lambda, so the same method answers three different questions.

**Easy Way to Remember:** **Predicate** asks a question. **Function** changes a value. **Consumer** uses a value. **Supplier** makes a value.

## Method References

A **method reference** is an even shorter way to write a lambda that only calls one existing method.

It uses a double colon `::`.

```text
name -> System.out.println(name)   // lambda
System.out::println                 // method reference
```

Both do exactly the same thing. The method reference just names the method instead of calling it.

There are four kinds:

| Kind | Method reference | Same as the lambda |
|---|---|---|
| Static method | `Integer::parseInt` | `s -> Integer.parseInt(s)` |
| Method of a particular object | `System.out::println` | `x -> System.out.println(x)` |
| Method of the parameter itself | `String::toUpperCase` | `s -> s.toUpperCase()` |
| Constructor | `ArrayList::new` | `() -> new ArrayList<>()` |

```java runnable title="Method references replace one-call lambdas"
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(List.of("ravi", "asha", "meena"));

        names.replaceAll(String::toUpperCase);
        names.forEach(System.out::println);

        Function<String, Integer> toNumber = Integer::parseInt;
        System.out.println("Parsed + 1: " + (toNumber.apply("41") + 1));

        Function<String, Integer> length = String::length;
        System.out.println("Length of MEENA: " + length.apply("MEENA"));

        Supplier<List<String>> newList = ArrayList::new;
        List<String> cart = newList.get();
        cart.add("Pen");
        System.out.println("New cart: " + cart);
    }
}
```

Expected output:

```text
RAVI
ASHA
MEENA
Parsed + 1: 42
Length of MEENA: 5
New cart: [Pen]
```

`String::toUpperCase` turned every name into capitals. `System.out::println` printed each one.

Use a method reference when the lambda only passes its parameter straight into one method. If the lambda does anything more, like `s -> s.toUpperCase() + "!"`, keep the lambda.

## Lambda vs Anonymous Classes

Both can implement an interface on the spot. They are not exactly the same.

```java runnable title="this means different things in each"
public class Main {
    String name = "Main object";

    public static void main(String[] args) {
        new Main().compare();
    }

    void compare() {
        Runnable anonymous = new Runnable() {
            String name = "Anonymous object";

            @Override
            public void run() {
                System.out.println("Anonymous class: this.name = " + this.name);
            }
        };

        Runnable lambda = () -> System.out.println("Lambda: this.name = " + this.name);

        anonymous.run();
        lambda.run();
    }
}
```

Expected output:

```text
Anonymous class: this.name = Anonymous object
Lambda: this.name = Main object
```

Inside the anonymous class, `this` means the anonymous object itself. Inside the lambda, `this` means the object of the surrounding code, here the `Main` object. A lambda does not create a new object scope.

`Runnable` is a built-in functional interface whose one method, `run()`, takes nothing and returns nothing.

| | Lambda expression | Anonymous class |
|---|---|---|
| Length | Usually one line | Several lines |
| Works with | Functional interfaces only (one abstract method) | Any interface or class, any number of methods |
| Can have its own fields? | No | Yes |
| What `this` means | The surrounding object | The anonymous object itself |
| Can extend a class? | No | Yes |
| Uses outer local variables | Only effectively final ones | Only effectively final ones |
| Use it when | You need a short piece of behaviour | You need several methods, fields, or to extend a class |

## Common mistakes

The following mistakes are common when writing lambda expressions and method references. Each row shows what you see, why it happens and how to fix it.

| Symptom | Cause | Fix |
|---|---|---|
| Syntax error at `a, b ->` | Several parameters without brackets | Write `(a, b) ->` |
| `missing return statement` in a lambda | A block body gives a value with no `return` | Add `return`, or remove the braces |
| `must be final or effectively final` | A captured variable was changed | Do not change variables a lambda uses |
| `is not a functional interface` | The interface has more than one abstract method | Use a single-method interface |
| `method println in class PrintStream cannot be applied` | Brackets were used in a method reference | Write `System.out::println` |
| A lambda becomes hard to read | Too much logic inside it | Move it into a named method |

## What to Remember

- A lambda is a short, nameless method: `(parameters) -> body`. It turns behaviour into a value.
- Lambdas were added in Java 8 to cut repeated code and to power streams.
- A lambda always fills in a functional interface, which has exactly one abstract method.
- One parameter needs no brackets. A one-line body needs no braces and no `return`.
- `Predicate` tests, `Function` converts, `Consumer` uses and `Supplier` creates.
- Method references, like `String::length` and `System.out::println`, are shortcuts for one-call lambdas.
- Lambdas are shorter than anonymous classes, but they only work with functional interfaces, and `this` means the surrounding object.

Next: Streams
