Lambda Expressions
Lambda expressions introduce a concise, functional style of programming in Java. They enable you to represent behavior as data, drastically reducing boilerplate code and improving readability—especially with collections, streams, and concurrency.
This is a very high-frequency interview topic (Java 8+).
What Is a Lambda Expression?
A lambda expression is an anonymous function—a block of code that:
- Has no name
- Can be passed as an argument
- Can be executed later
It is primarily used to implement functional interfaces.
Basic Syntax
(parameters) -> expression
or
(parameters) -> {
statements;
}
Examples
() -> System.out.println("Hello");
(a, b) -> a + b
(int a, int b) -> {
return a * b;
}
Functional Interface (Foundation of Lambdas)
A functional interface has exactly one abstract method.
@FunctionalInterface
interface Calculator {
int add(int a, int b);
}
- ✔ Can have default and static methods
- ✔ @FunctionalInterface is optional but recommended
Lambda with Functional Interface
Without Lambda (Old Style)
Calculator c = new Calculator() {
public int add(int a, int b) {
return a + b;
}
};
With Lambda (Java 8+)
Calculator c = (a, b) -> a + b;
- ✔ Cleaner
- ✔ Readable
- ✔ Less boilerplate
Common Built-in Functional Interfaces
| Interface | Method | Purpose |
|---|---|---|
| Runnable | run() | No input, no output |
| Consumer<T> | accept(T) | Input, no output |
| Supplier<T> | get() | No input, output |
| Function<T, R> | apply(T) | Input → output |
| Predicate<T> | test(T) | Boolean condition |
Examples
Runnable r = () -> System.out.println("Running");
Predicate isEven = n -> n % 2 == 0;
Function length = s -> s.length();
Lambda with Collections (Very Common)
Iterating a List
Listlist = Arrays.asList("Java", "Python", "C++"); list.forEach(s -> System.out.println(s));
Sorting with Lambda
Collections.sort(list, (a, b) -> a.compareTo(b));
Lambda with Threads
Thread t = new Thread(() -> {
System.out.println("Thread running");
});
t.start();
- ✔ Uses Runnable internally
- ✔ Preferred modern approach
Parameter Rules
(a, b) -> a + b // type inferred
(int a, int b) -> a + b // explicit type
❌ Mixing typed and untyped parameters is not allowed
Lambda Body Rules
- Single statement → braces optional
- Multiple statements → braces + return required
a -> a * a
a -> {
int result = a * a;
return result;
}
Variable Capture (Effectively Final)
Lambdas can access local variables only if they are final or effectively final.
int x = 10;
Runnable r = () -> {
System.out.println(x);
};
❌ Modifying x later → compilation error
this Keyword in Lambda (Interview Trap)
- this refers to enclosing class, not lambda
- Unlike anonymous inner classes
this.toString(); // enclosing object
Lambda vs Anonymous Inner Class
| Aspect | Lambda | Anonymous Class |
|---|---|---|
| Code size | Minimal | Verbose |
| this reference | Enclosing class | Inner class |
| Readability | High | Low |
| Performance | Better | Slight overhead |
Where Lambdas Are Used Heavily
- Streams API
- Collections sorting/filtering
- Event handling
- Concurrency (Runnable, Callable)
- Functional-style programming
Limitations of Lambda Expressions
- Can be used only with functional interfaces
- Cannot have state (no instance variables)
- Cannot throw checked exceptions directly (without handling)
- Overuse can reduce readability if complex
Common Beginner Mistakes
- Trying to use lambda with non-functional interfaces
- Writing complex logic inside lambda
- Confusing this behavior
- Ignoring readability
- Forgetting variable must be effectively final
Interview-Ready Answers
Short Answer
Lambda expressions provide a concise way to implement functional interfaces in Java.
Detailed Answer
In Java, lambda expressions are anonymous functions used to implement functional interfaces. Introduced in Java 8, they reduce boilerplate code, improve readability, and enable functional programming features such as streams and parallel processing.
Key Takeaway
Lambda expressions = behavior as data. They make Java cleaner, more expressive, and functional, especially when combined with functional interfaces and streams.
Lambda Expression Examples
1. Lambda with No Parameters
Runnable r = () -> System.out.println("Hello Lambda");
new Thread(r).start();
2. Lambda with One Parameter
interface Printer {
void print(String msg);
}
class Demo {
public static void main(String[] args) {
Printer p = msg -> System.out.println(msg);
p.print("Java Lambda");
}
}
3. Lambda with Multiple Parameters
interface Adder {
int add(int a, int b);
}
class Demo {
public static void main(String[] args) {
Adder a = (x, y) -> x + y;
System.out.println(a.add(10, 20));
}
}
4. Lambda with Explicit Return
Adder a = (x, y) -> {
return x + y;
};
5. Lambda Without Return Keyword (Expression Body)
Adder a = (x, y) -> x + y;
6. Lambda with Runnable (Thread Creation)
new Thread(() -> {
System.out.println("Thread using Lambda");
}).start();
7. Lambda with Comparator
import java.util.*;
class Demo {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(3, 1, 2);
Collections.sort(list, (a, b) -> a - b);
System.out.println(list);
}
}
8. Lambda with Comparator (Descending Order)
Collections.sort(list, (a, b) -> b - a);
9. Lambda with forEach()
import java.util.*;
class Demo {
public static void main(String[] args) {
List<String> list = Arrays.asList("Java", "Selenium");
list.forEach(s -> System.out.println(s));
}
}
10. Lambda with Method Reference
list.forEach(System.out::println);
11. Lambda with Predicate
import java.util.function.Predicate;
class Demo {
public static void main(String[] args) {
Predicate<Integer> isEven = x -> x % 2 == 0;
System.out.println(isEven.test(10));
}
}
12. Lambda with Function
import java.util.function.Function;
class Demo {
public static void main(String[] args) {
Function<String, Integer> length = s -> s.length();
System.out.println(length.apply("Lambda"));
}
}
13. Lambda with Consumer
import java.util.function.Consumer;
class Demo {
public static void main(String[] args) {
Consumer<String> c = s -> System.out.println(s.toUpperCase());
c.accept("java");
}
}
14. Lambda with Supplier
import java.util.function.Supplier;
class Demo {
public static void main(String[] args) {
Supplier<Double> random = () -> Math.random();
System.out.println(random.get());
}
}
15. Lambda with Stream.filter()
import java.util.*;
class Demo {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4);
list.stream()
.filter(x -> x % 2 == 0)
.forEach(System.out::println);
}
}
16. Lambda with map()
list.stream()
.map(x -> x * 2)
.forEach(System.out::println);
17. Lambda Capturing Local Variable (Effectively Final)
class Demo {
public static void main(String[] args) {
int x = 10;
Runnable r = () -> System.out.println(x);
r.run();
}
}
Rule: Variable must be effectively final.
18. ❌ Modifying Local Variable Inside Lambda (Trap)
int x = 10;
Runnable r = () -> {
// x++; // ❌ compilation error
};
19. Lambda vs Anonymous Class
// Anonymous class
Runnable r1 = new Runnable() {
public void run() {
System.out.println("Old way");
}
};
// Lambda
Runnable r2 = () -> System.out.println("Lambda way");
20. Lambda with Custom Functional Interface
@FunctionalInterface
interface Calculator {
int operate(int a, int b);
}
class Demo {
public static void main(String[] args) {
Calculator c = (a, b) -> a * b;
System.out.println(c.operate(3, 4));
}
}
21. Lambda with Exception Handling
Runnable r = () -> {
try {
Thread.sleep(100);
} catch (Exception e) {
System.out.println("Handled");
}
};
22. Lambda in ExecutorService
import java.util.concurrent.*;
class Demo {
public static void main(String[] args) {
ExecutorService ex = Executors.newSingleThreadExecutor();
ex.execute(() -> System.out.println("Task running"));
ex.shutdown();
}
}
23. Lambda Returning Object
Supplier<String> s = () -> "Lambda Result";
System.out.println(s.get());
24. ❌ Lambda Cannot Replace Non-Functional Interface
// Interface with multiple abstract methods ❌
// Lambda not allowed
25. Interview Summary – Lambda Expressions
(parameters) -> expression
(parameters) -> { statements }
Key Points
- Requires functional interface
- Reduces boilerplate
- Supports collections, streams, threads
- Variables must be effectively final
- Improves readability & maintainability