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
RunnableandComparator
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:
| Part | Description |
|---|---|
(parameters) | Input values. Can be empty () or have types or just names |
-> | The "arrow" โ separates params from body |
expression | What 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โ hasrun()Comparator<T>โ hascompare()Callable<T>โ hascall()
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
returnin a multi-line lambda body โ โ Fix: Always addreturninside{}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.,
isAdultnotx)
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
Related Topicsโ
- Functional Interfaces (
@FunctionalInterface) - Method References
- Stream API
- Anonymous Inner Classes
Next Lessonโ
Lesson 2 โ Functional Interfaces