On this page
Lambda Expressions
Lambda expressions (since Java 8) provide a concise way to represent anonymous functions. They are the foundation of functional programming in Java and work with the Stream API and functional interfaces.
Syntax
(parameters) -> expression
(parameters) -> { statements; }
Examples:
// No parameters
Runnable r = () -> System.out.println("Hello");
// One parameter (parentheses optional)
Consumer<String> printer = s -> System.out.println(s);
// Multiple parameters
BinaryOperator<Integer> add = (a, b) -> a + b;
// Block body
Comparator<String> byLength = (a, b) -> {
int diff = a.length() - b.length();
return Integer.compare(diff, 0);
};
Functional Interfaces
A lambda can only be assigned to a functional interface — an interface with exactly one abstract method:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
Calculator multiply = (a, b) -> a * b;
System.out.println(multiply.calculate(6, 7)); // 42
Common Use Cases
Collections
List<String> names = List.of("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
names.sort((a, b) -> a.compareToIgnoreCase(b));
names.removeIf(name -> name.startsWith("A"));
Threads
new Thread(() -> System.out.println("Running in thread")).start();
Event Handlers
button.setOnAction(event -> System.out.println("Clicked!"));
Method References
Shorthand when a lambda simply calls an existing method:
| Type | Syntax | Example |
|---|---|---|
| Static method | ClassName::method |
Integer::parseInt |
| Instance method | instance::method |
System.out::println |
| Instance method of arbitrary object | ClassName::method |
String::compareToIgnoreCase |
| Constructor | ClassName::new |
ArrayList::new |
List<String> names = List.of("alice", "bob");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
Variable Capture
Lambdas can access effectively final local variables and instance fields:
int factor = 10;
Function<Integer, Integer> multiply = n -> n * factor;
// factor = 20; // Compile error — factor is no longer effectively final
Lambdas cannot modify local variables from the enclosing scope.
Lambda vs Anonymous Inner Class
// Anonymous inner class
Runnable r1 = new Runnable() {
public void run() {
System.out.println("Hello");
}
};
// Lambda
Runnable r2 = () -> System.out.println("Hello");
Lambdas do not create a separate .class file per instance (uses invokedynamic), making them more efficient for short callbacks.
Best Practices
- Keep lambdas short — extract complex logic into named methods
- Prefer method references when they improve readability
- Use meaningful parameter names for multi-parameter lambdas
- Avoid side effects inside lambdas passed to Stream operations when possible