Lambda Expressions
Write concise anonymous function expressions using Java lambdas to replace verbose anonymous class syntax.
Overview
Key Points
- •Syntax: (params) -> expression or (params) -> { body; return value; }
- •Parameter types can be omitted when the compiler can infer them
- •Single-parameter lambdas can omit parentheses: x -> x * 2
- •No-parameter lambdas still need empty parentheses: () -> System.out.println("hi")
- •Lambdas can only be used where a functional interface is expected
- •Lambdas capture effectively-final local variables from the enclosing scope
- •this inside a lambda refers to the enclosing class, not the lambda itself
- •Method references (::) are shorthand for certain lambda patterns (covered in J053)
Examples
Lambda as Runnable and Comparator
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Runnable with lambda (no parameters, no return)
Runnable greet = () -> System.out.println("Hello from lambda!");
greet.run();
// Comparator with lambda
List<String> names = new ArrayList<>(List.of("Charlie","Alice","Bob","Diana"));
names.sort((a, b) -> a.compareTo(b));
System.out.println("Sorted: " + names);
// Sort by length
names.sort((a, b) -> Integer.compare(a.length(), b.length()));
System.out.println("By length: " + names);
}
}names.sort((a, b) -> ...) replaces the verbose new Comparator<String>() { public int compare(String a, String b) { ... } } anonymous class.
Lambda with forEach
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Print each number
numbers.forEach(n -> System.out.print(n + " "));
System.out.println();
// Print only evens
numbers.forEach(n -> {
if (n % 2 == 0) System.out.print(n + " ");
});
System.out.println();
// Multi-line body needs braces and explicit return if returning a value
List<String> words = List.of("hello", "world", "java");
words.forEach(w -> {
String upper = w.toUpperCase();
System.out.println(upper);
});
}
}Single-expression lambdas omit braces and return. Multi-statement lambdas use braces.
Capturing variables from the enclosing scope
import java.util.List;
public class Main {
public static void main(String[] args) {
String prefix = "Item: "; // effectively final
int multiplier = 3; // effectively final
List<String> items = List.of("apple", "banana", "cherry");
items.forEach(item -> System.out.println(prefix + item));
List<Integer> nums = List.of(1, 2, 3);
nums.forEach(n -> System.out.println(n * multiplier));
}
}Lambdas can use local variables from the enclosing method if those variables are effectively final (never reassigned after their initial assignment).
Common Mistakes
- Trying to modify a captured local variable inside a lambda. It must be effectively final; use an array or a field instead if you need mutation
- Using a lambda where the target type is not a functional interface. An interface must have exactly one abstract method
- Forgetting braces and return when the lambda body has multiple statements
Note
The simplest lambda form is the expression lambda: x -> x * 2. Reserve the block form (x -> { ... }) for cases with multiple statements. Keeping lambdas short makes them readable.
Exercises
Write Java code and click Run to execute it instantly. When your output looks correct, mark as done.
Completed: 0 / 4 exercises
Knowledge Check
Question 1 of 4