Table of Contents
Introduction
Lambda expressions were introduced in Java 8, which revolutionized the way developers can write Java code. They offer a concise and elegant way to express functional logic. In this blog, we’ll dive deep into lambda expressions, their syntax, benefits, and how they integrate seamlessly with functional interfaces.
What are Lambda Expressions?
- Essentially, a lambda expression is a compact way to implement a functional interface‘s single abstract method.
- Explain lambda expressions as anonymous functions that can be passed as arguments or assigned to variables
- Think of it as an anonymous function, a function without a name.
- Basic Syntax:
(parameters) -> { body }
Syntax of Lambda Expressions
A lambda expression in Java has the following syntax:
(parameters) -> { body }
- Parameters: This is a comma-separated list of input parameters. If there are no parameters, you can use empty parentheses
()
. If there’s only one parameter, parentheses are optional. - Arrow Token
->
: This is used to link parameters and the body of the lambda expression. - Body: This contains expressions and statements for the lambda expression. If the body has a single statement, the curly braces
{}
are optional.
Examples of Lambda Expressions
Here are examples of different types of lambda expressions:
- No Parameters
A lambda expression with no parameters simply returns a value. For example:
() -> "Hello, World!"
This lambda expression takes no parameters and returns the string “Hello, World!”.
Runnable task = () -> System.out.println("Task running!");
- Single Parameter
A lambda expression with a single parameter can be written with or without parentheses. For example:
x -> x * x
This lambda expression takes one parameter x
and returns the square of x
.
Single Parameter With data type:
Comparator<String> strComparator = (String s1) -> s1.length();
Single Parameter Without data type:
Predicate isPositive = n -> n > 0;
- Multiple Parameters
A lambda expression with multiple parameters must be enclosed in parentheses. For example:
(a, b) -> a * b
This lambda expression takes two parameters a
and b
and returns their product.
Function squareFunction = (x, y) -> x * y;
Why Use Lambda Expressions?
- Concise Code: Lambda expressions streamline code, making it more readable, especially when used with APIs like the Streams API.
- Functional Programming: They encourage a functional style where you treat functions as first-class citizens.
- Efficiency with Collections: Lambda expressions work beautifully for iterating, filtering, and transforming collections.
Functional Interfaces: The Key Connection
- Functional interfaces are the backbone of lambda expressions. They have only one abstract method, serving as the blueprint for the lambda’s implementation
- Common Examples:
Runnable
(Task execution)Comparator
(Object comparison)Consumer
(Accepts an input)Supplier
(Provides an output)Predicate
(Tests a condition)
Understanding java.util.function
for Lambda Expressions:
The java.util.function
package in Java 8 contains various functional interfaces that are commonly used with lambda expressions. Some of the interfaces in this package include:
Function
: Represents a function that accepts one argument and produces a result.Predicate
: Represents a predicate (boolean-valued function) of one argument.Consumer
: Represents an operation that accepts a single input argument and returns no result.Supplier
: Represents a supplier of results.BiFunction
,BiPredicate
,BiConsumer
: Represents functions, predicates, and consumers that accept two arguments.
These functional interfaces are widely used in Java 8 and later versions when working with lambda expressions, streams, and other functional programming concepts.
Lambda Expression Examples
Sorting a List:
List<String> names = Arrays.asList("Alice", "Charlie", "Bob");
Collections.sort(names, (s1, s2) -> s1.co
mpareToIgnoreCase(s2));
Filtering Elements:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
Mapping Data:
List<String> names = Arrays.asList("Alice", "Charlie", "Bob");
List<String> lowerCaseNames = names.stream().map(String::toLowerCase).collect(Collectors.toList());
Return Types in Lambda Expressions
- The return type of a lambda mirrors the return type of the functional interface’s abstract method.
Lambda Expressions: Beyond the Basics
- Block Lambdas: For multiple statements:
(x, y) -> { System.out.println(x + y); return x * y; }
- Method References: Shorthand for lambdas that invoke existing methods:
ClassName::methodName