Java 8 Explained: Mastering Lambda Expressions
Java 8 introduced lambda expressions, a powerful feature that enables functional programming in Java. Lambda expressions make writing concise and readable code easier by allowing you to pass behavior (functions) as arguments.
What is a Lambda Expression?
A lambda expression is an anonymous function (a function without a name) that can implement a functional interface.
Syntax:
(parameters) -> expression
// Or for multiple statements:
(parameters) -> { statements; }
Components of Lambda Expressions
- Parameters: Similar to method parameters but no need to specify the type (Java infers it).
- Arrow Token (
->
): Separates parameters and the body. - Body: Contains the logic, which could be a single expression or a block.
Functional Interface
A functional interface is an interface with a single abstract method (SAM). Example:
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}
Common Functional Interfaces in java.util.function
package:
Predicate<T>
: Represents a condition (returns boolean).Function<T, R>
: Transforms an input to an output.Consumer<T>
: Performs an action on an input.Supplier<T>
: Provides a result without input.
Basic Examples
Example 1: Lambda for a Runnable
Before Java 8:
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Running...");
}
};
new Thread(runnable).start();
With Lambda:
Runnable runnable = () -> System.out.println("Running...");
new Thread(runnable).start();
Example 2: Using Comparator
Before Java 8:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a - b;
}
};
With Lambda:
Comparator<Integer> comparator = (a, b) -> a - b;
Example 3: Iterating a List
Before Java 8:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
for (String name : names) {
System.out.println(name);
}
With Lambda:
names.forEach(name -> System.out.println(name));
Using Built-In Functional Interfaces
Example 1: Predicate<T>
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // Output: true
Example 2: Function<T, R>
Function<String, Integer> stringLength = str -> str.length();
System.out.println(stringLength.apply("Lambda")); // Output: 6
Example 3: Consumer<T>
Consumer<String> print = msg -> System.out.println(msg);
print.accept("Hello, Lambda!"); // Output: Hello, Lambda!
Example 4: Supplier<T>
Supplier<Double> randomValue = () -> Math.random();
System.out.println(randomValue.get()); // Output: Random number
Method References
Lambda expressions can be replaced with method references if the logic is already implemented:
// Lambda
Consumer<String> print = msg -> System.out.println(msg);
// Method Reference
Consumer<String> print = System.out::println;
Advantages of Lambda Expressions
- Concise Code: Reduces boilerplate.
- Readability: Easy to understand intent.
- Functional Style: Supports functional programming constructs.
Common Use Cases
- Implementing callbacks and listeners.
- Sorting collections.
- Stream API operations (e.g., filtering, mapping).
- Simplifying threading and concurrency logic.
Stream API Example
Lambda works beautifully with the Stream API:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.filter(n -> n % 2 == 0) // Only even numbers
.map(n -> n * n) // Square each number
.forEach(System.out::println); // Print results
Conclusion
Lambda expressions are a core feature in Java 8 that simplifies writing and reading code. Mastering them will make you more proficient in modern Java programming.
_
Follow us for more insightful and valuable articles!