Skip to main content

Lambda Expressions

Reading Time: 8 Minutes
Difficulty: Beginner


Topic Summaryโ€‹

A lambda expression is a short block of code that takes in parameters and returns a value. Think of it as a mini function that you can write inline โ€” without needing to give it a name. Java 8 introduced lambdas to make code shorter and easier to read, especially when working with collections and event handling.


What You'll Learnโ€‹

  • What a lambda expression is and why it exists
  • The syntax of lambda expressions
  • How lambdas replace anonymous inner classes
  • Multi-line lambda expressions
  • Real examples with Runnable and Comparator

Prerequisitesโ€‹

  • Basic Java syntax (classes, methods, interfaces)
  • Understanding of interfaces in Java

Explanationโ€‹

What Problem Do Lambdas Solve?โ€‹

Before Java 8, whenever you needed to pass behavior (a piece of code) to a method, you had to create an anonymous inner class. Anonymous classes are verbose and messy. Let's look at an example:

// Old way โ€” anonymous inner class
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Running!");
}
};

That's 5 lines of code just to say "print Running!". With a lambda expression, the same thing becomes:

// New way โ€” lambda
Runnable r = () -> System.out.println("Running!");

Just one line. That's the power of lambdas.


Lambda Syntaxโ€‹

The general syntax of a lambda expression is:

(parameters) -> expression

Or for multiple statements:

(parameters) -> {
statement1;
statement2;
return value;
}

Let's break it down:

PartDescription
(parameters)Input values. Can be empty () or have types or just names
->The "arrow" โ€” separates params from body
expressionWhat the lambda does / returns

Lambda Syntax Rulesโ€‹

1. No parameters:

() -> System.out.println("Hello")

2. One parameter (parentheses optional):

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

3. Multiple parameters:

(a, b) -> a + b

4. With explicit types (optional):

(int a, int b) -> a + b

5. Multi-line body (needs curly braces and return):

(a, b) -> {
int sum = a + b;
return sum;
}

Where Can You Use Lambdas?โ€‹

Lambdas can only be used where a functional interface is expected. A functional interface is any interface that has exactly one abstract method. Examples:

  • Runnable โ€” has run()
  • Comparator<T> โ€” has compare()
  • Callable<T> โ€” has call()

The compiler figures out which method you're implementing based on the interface type.


Multi-line Lambdasโ€‹

When your lambda has more than one line of logic, use curly braces:

Comparator<String> comp = (s1, s2) -> {
int lengthDiff = s1.length() - s2.length();
if (lengthDiff != 0) return lengthDiff;
return s1.compareTo(s2);
};

Why Lambdas = Cleaner Codeโ€‹

  • Less boilerplate: No need to write full anonymous class
  • More readable: Intent is clearer at a glance
  • Enables functional style: Pass behavior as arguments naturally
  • Works with Stream API: Powers Java 8's stream pipeline

Real-World Analogyโ€‹

Think of a lambda like a sticky note instruction. Instead of hiring a full employee (anonymous class), writing their contract, and assigning them a desk โ€” you just stick a note on the fridge saying "wash dishes". It's quick, direct, and disposable. Lambdas are your sticky notes for behavior.


Code Exampleโ€‹

Example 1: Runnable with Lambdaโ€‹

public class LambdaDemo {
public static void main(String[] args) {

// Old way โ€” anonymous class
Runnable oldWay = new Runnable() {
@Override
public void run() {
System.out.println("Old way: Running in a thread!");
}
};

// New way โ€” lambda expression
Runnable newWay = () -> System.out.println("New way: Running in a thread!");

// Run both
oldWay.run();
newWay.run();
}
}

Outputโ€‹

Old way: Running in a thread!
New way: Running in a thread!

Example 2: Comparator with Lambdaโ€‹

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class ComparatorLambda {
public static void main(String[] args) {
List<String> names = Arrays.asList("Charlie", "Alice", "Bob", "Diana");

// Old way โ€” anonymous class
names.sort(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
System.out.println("Sorted (old way): " + names);

// New way โ€” lambda
names.sort((a, b) -> b.compareTo(a)); // reverse sort
System.out.println("Sorted (lambda): " + names);
}
}

Outputโ€‹

Sorted (old way): [Alice, Bob, Charlie, Diana]
Sorted (lambda): [Diana, Charlie, Bob, Alice]

Example 3: Multi-line Lambdaโ€‹

import java.util.Arrays;
import java.util.List;

public class MultiLineLambda {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);

// Multi-line lambda for sorting with custom logic
numbers.sort((a, b) -> {
System.out.println("Comparing " + a + " and " + b);
return Integer.compare(a, b);
});

System.out.println("Sorted: " + numbers);
}
}

Outputโ€‹

Comparing 2 and 5
Comparing 8 and 2
...
Sorted: [1, 2, 3, 5, 8, 9]

Common Mistakesโ€‹

  • โŒ Mistake: Using a lambda where the interface has more than one abstract method โ†’ โœ… Fix: Lambdas only work with functional interfaces (one abstract method)
  • โŒ Mistake: Forgetting return in a multi-line lambda body โ†’ โœ… Fix: Always add return inside {} if the lambda should return a value
  • โŒ Mistake: Modifying local variables from the enclosing method inside a lambda โ†’ โœ… Fix: Local variables used in lambdas must be effectively final (not changed after assignment)
  • โŒ Mistake: Using explicit types inconsistently โ€” e.g., (int a, b) โ†’ โœ… Fix: Either provide types for ALL params or NONE: (int a, int b) or (a, b)

Best Practicesโ€‹

  • Keep lambdas short โ€” if it's more than 3-4 lines, consider using a named method and a method reference instead
  • Use lambda expressions with the Stream API for clean data processing pipelines
  • Avoid complex logic in lambdas โ€” they should be readable at a glance
  • Prefer lambdas over anonymous classes โ€” they're the modern Java way
  • Name your lambda variables meaningfully (e.g., isAdult not x)

Interview Questionsโ€‹

Q: What is a lambda expression in Java?
A: A lambda expression is an anonymous function (no name, no class) that can be passed around as a value. It provides a short syntax for implementing functional interfaces. Introduced in Java 8, it replaces verbose anonymous inner classes.

Q: What is the syntax of a lambda expression?
A: (parameters) -> expression or (parameters) -> { statements; }. Parentheses are optional for single parameters, and the return keyword is optional for single-expression bodies.

Q: Can lambda expressions access variables from the enclosing scope?
A: Yes, but only effectively final variables โ€” variables that are assigned once and never changed. This is because lambda expressions may be executed at a different time, and mutable local variables could cause unpredictable behavior.

Q: What is the difference between a lambda and an anonymous class?
A: Both implement an interface, but lambdas are shorter syntax, don't create a new scope (they share this with enclosing class), and can only implement functional interfaces. Anonymous classes can implement any interface or extend a class and have their own this.

Q: Can a lambda expression throw a checked exception?
A: Only if the functional interface's abstract method declares that exception in its throws clause. Otherwise, you must catch it inside the lambda body.


Quick Revisionโ€‹

โœ” Lambda = short anonymous function: (params) -> body
โœ” Replaces anonymous inner classes for functional interfaces
โœ” Works only with interfaces that have exactly one abstract method
โœ” Multi-line lambdas use {} and explicit return
โœ” Local variables used in lambdas must be effectively final


  • Functional Interfaces (@FunctionalInterface)
  • Method References
  • Stream API
  • Anonymous Inner Classes

Next Lessonโ€‹

Lesson 2 โ€” Functional Interfaces