Java tutorials > Modern Java Features > Java 8 and Later > What are lambda expressions and how do they work?
What are lambda expressions and how do they work?
Lambda expressions, a cornerstone of Java 8 and later, provide a concise way to represent anonymous functions. They enable you to treat functionality as a method argument, or code as data. This tutorial explores lambda expressions, covering their syntax, functionality, and usage with code examples.
Introduction to Lambda Expressions
Lambda expressions are essentially anonymous methods – methods without a name. They are characterized by: The general syntax is
(parameters) -> { body }
.
Basic Syntax of Lambda Expressions
Let's break down the syntax:
() -> System.out.println("Hello, Lambda!");
: A lambda expression with no parameters that prints "Hello, Lambda!".(int x, int y) -> x + y;
: A lambda expression that takes two integer parameters (x and y) and returns their sum. The return type is inferred as int
.x -> x * x;
: A lambda expression taking a single parameter x
and returning its square. Parentheses around a single parameter are optional.
() -> System.out.println("Hello, Lambda!");
(int x, int y) -> x + y;
x -> x * x;
Functional Interfaces
Lambda expressions are primarily used with functional interfaces. A functional interface is an interface with only one abstract method. Java provides several built-in functional interfaces in the java.util.function
package, such as:
Function
: Represents a function that accepts one argument and produces a result.Consumer
: Represents an operation that accepts a single input argument and returns no result.Predicate
: Represents a predicate (boolean-valued function) of one argument.Supplier
: Represents a supplier of results.
Lambda Expressions with Functional Interfaces - Example
In this example: The second part shows how to use the
Function
interface from java.util.function
.x -> x * x
and assign it to a Function
variable named square
. This lambda takes an integer and returns its square.apply()
method of the Function
interface to execute the lambda expression with an input of 5.Consumer
interface.
import java.util.function.Function;
public class LambdaExample {
public static void main(String[] args) {
// Using Function interface to square a number
Function<Integer, Integer> square = x -> x * x;
int result = square.apply(5); // Applies the function
System.out.println("Square of 5: " + result); // Output: Square of 5: 25
//Using Consumer to print a message.
java.util.function.Consumer<String> printMessage = message -> System.out.println(message);
printMessage.accept("This is a Consumer example."); // Output: This is a Consumer example.
}
}
Concepts Behind the Snippet
The core concept is functional programming. Lambda expressions enable treating functions as first-class citizens, meaning functions can be passed as arguments, returned from other functions, and assigned to variables. This allows for more concise and flexible code, particularly when working with collections and streams.
Real-Life Use Case Section
A common use case is processing collections using streams. The example above shows how to use lambda expressions with streams to: Lambda expressions make stream operations much more readable and concise.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamLambdaExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Using lambda to filter even numbers and then square them
List<Integer> evenSquares = numbers.stream()
.filter(x -> x % 2 == 0) // Filter even numbers
.map(x -> x * x) // Square the even numbers
.collect(Collectors.toList()); // Collect the results into a list
System.out.println("Even Squares: " + evenSquares); // Output: Even Squares: [4, 16, 36, 64, 100]
}
}
Best Practices
System.out::println
) for even more concise code.
Interview Tip
Be prepared to explain the difference between lambda expressions and anonymous classes. Lambda expressions can only be used with functional interfaces, whereas anonymous classes can implement interfaces with multiple methods or extend concrete classes. Lambda expressions are also generally more lightweight and efficient.
When to use them
Use lambda expressions when:
Memory footprint
Lambda expressions generally have a smaller memory footprint than anonymous classes, especially when used frequently. The exact difference depends on the JVM implementation and the complexity of the lambda, but lambdas are often compiled to more efficient bytecode.
Alternatives
Alternatives to lambda expressions include:
Pros
Cons
FAQ
-
Can I use lambda expressions with any interface?
No, you can only use lambda expressions with functional interfaces – interfaces with a single abstract method. -
What is a method reference?
A method reference is a shorthand notation for a lambda expression that simply calls an existing method. For example,System.out::println
is a method reference that calls theprintln
method of theSystem.out
object. -
Are lambda expressions more efficient than anonymous classes?
Generally, yes. Lambda expressions are often compiled to more efficient bytecode and have a smaller memory footprint than anonymous classes.