Java Lambda Expressions, introduced in Java 8, provide a clear and concise way to represent one method interface using an expression.
They are particularly useful for functional interfaces, which are interfaces with a single abstract method.
Lambda expressions help simplify code by eliminating the need for anonymous classes, making code more readable and easier to maintain.
Table of Contents
Syntax of Lambda Expressions
The syntax of a lambda expression is:
(parameters) -> expression (parameters) -> { statements; }
- (parameters): The input parameters for the method.
- ->: The arrow token separates parameters from the expression or block of code.
- expression or { statements; }: The body of the lambda expression, which can either be a single expression or a block of statements.
Key Points about Lambda Expressions
- Functional Interface Requirement: Lambda expressions can only be used with functional interfaces.
- Type Inference: The types of parameters can be inferred by the compiler.
- Conciseness: Lambdas simplify code by reducing boilerplate syntax.
Example 1: Basic Lambda Expression with Runnable
The Runnable interface is a functional interface with a single run() method, which is ideal for a lambda expression.
Example
public class LambdaRunnableExample { public static void main(String[] args) { // Using lambda expression for Runnable Runnable task = () -> System.out.println("Task is running"); // Start a thread with the lambda expression Thread thread = new Thread(task); thread.start(); } }
Explanation
- We create a Runnable using a lambda expression instead of an anonymous inner class.
- Runnable task = () -> System.out.println(“Task is running”); represents the run() method of Runnable.
Output
Task is running
Example 2: Lambda Expression with Parameters
This example uses a lambda expression with parameters in the Comparator interface to compare two strings by their lengths.
Example
import java.util.Arrays; import java.util.Comparator; public class LambdaComparatorExample { public static void main(String[] args) { String[] names = { "John", "Alice", "Bob", "Charlie" }; // Using lambda expression to sort by string length Arrays.sort(names, (s1, s2) -> Integer.compare(s1.length(), s2.length())); // Display sorted array System.out.println(Arrays.toString(names)); } }
Explanation
- (s1, s2) -> Integer.compare(s1.length(), s2.length()) is a lambda expression that implements the compare method of Comparator<String>.
- This lambda expression sorts strings by their lengths.
Output
[Bob, John, Alice, Charlie]
Example 3: Using Lambda with Custom Functional Interface
You can define your own functional interface to use with lambda expressions.
Example
@FunctionalInterface interface Greeting { void sayHello(String name); } public class LambdaCustomInterfaceExample { public static void main(String[] args) { // Lambda expression for Greeting interface Greeting greeting = name -> System.out.println("Hello, " + name + "!"); // Use the lambda expression greeting.sayHello("Alice"); greeting.sayHello("Bob"); } }
Explanation
- Greeting is a custom functional interface with a single method sayHello.
- name -> System.out.println(“Hello, ” + name + “!”) is a lambda that implements sayHello to greet a user by name.
Output
Hello, Alice! Hello, Bob!
Example 4: Lambda Expression with Block of Statements
If the lambda body has multiple statements, enclose them in curly braces { }.
Example
@FunctionalInterface interface MathOperation { int operate(int a, int b); } public class LambdaBlockExample { public static void main(String[] args) { // Lambda expression with multiple statements in the body MathOperation addition = (a, b) -> { System.out.println("Adding " + a + " and " + b); return a + b; }; int result = addition.operate(5, 3); System.out.println("Result: " + result); } }
Explanation
- (a, b) -> { System.out.println(“Adding ” + a + ” and ” + b); return a + b; } has a block of statements within the lambda.
- The lambda prints each operand before performing the addition.
Output
Adding 5 and 3 Result: 8
Example 5: Lambda Expressions with Predicate Functional Interface
The Predicate<T> interface is a generic functional interface that accepts a single argument and returns a boolean result. It’s commonly used in filter operations.
Example
import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class LambdaPredicateExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // Predicate to check if a string starts with "A" Predicate<String> startsWithA = s -> s.startsWith("A"); // Filter and print names starting with "A" names.stream() .filter(startsWithA) .forEach(System.out::println); } }
Explanation
- Predicate<String> startsWithA = s -> s.startsWith(“A”) checks if a string starts with “A”.
- filter(startsWithA) filters the stream to include only names that start with “A”.
Output
Alice
Example 6: Using Lambda with Function Interface
The Function<T, R> interface is a functional interface that accepts one argument of type T and returns a result of type R.
Example
import java.util.function.Function; public class LambdaFunctionExample { public static void main(String[] args) { // Function to calculate the square of an integer Function<Integer, Integer> square = x -> x * x; // Use the function System.out.println("Square of 5: " + square.apply(5)); System.out.println("Square of 10: " + square.apply(10)); } }
Explanation
- Function<Integer, Integer> square = x -> x * x; is a lambda that calculates the square of a number.
- apply is called with the argument to calculate and print the square.
Output
Square of 5: 25 Square of 10: 100
Example 7: Method References with Lambda Expressions
Java provides method references as a shorthand notation for lambdas that call a single method. They are often used to refer to existing methods or constructors.
Example
import java.util.Arrays; import java.util.List; public class LambdaMethodReferenceExample { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // Method reference instead of lambda expression names.forEach(System.out::println); } }
Explanation
- System.out::println is a method reference that refers to System.out.println(String).
- This replaces a lambda that would have called println on each name in the list.
Output
Alice Bob Charlie
Example 8: Lambda Expression with BiFunction
The BiFunction<T, U, R> functional interface takes two arguments of types T and U, and returns a result of type R.
Example
import java.util.function.BiFunction; public class LambdaBiFunctionExample { public static void main(String[] args) { // BiFunction to concatenate two strings with a space BiFunction<String, String, String> concatenate = (s1, s2) -> s1 + " " + s2; // Use the BiFunction String result = concatenate.apply("Hello", "World"); System.out.println("Concatenated String: " + result); } }
Explanation
- (s1, s2) -> s1 + ” ” + s2 is a lambda that concatenates two strings with a space in between.
- The apply method is called to concatenate “Hello” and “World”.
Output
Concatenated String: Hello World
Summary
Java lambda expressions simplify working with functional interfaces, making code more concise and readable.
Key points include:
- Syntax: (parameters) -> expression or (parameters) -> { statements }.
- Functional Interfaces: Lambdas work with interfaces that have a single abstract method.
- Common Functional Interfaces:
- Runnable, Comparator, Predicate, Function, BiFunction, etc.
- Method References: Provide a shorthand for lambdas that only call one method.
Lambda expressions are a core feature for functional programming in Java, making it easier to work with collections, streams, and functional interfaces.