When we write Java programs, we often create methods or small blocks of code to perform a particular task. Sometimes, however, the code we need is very small, and creating a separate method or class just for that task can feel unnecessary.
This is where lambda expressions become useful.
A lambda expression is a short way of writing a piece of code that can be passed around and executed when needed.
The basic syntax looks like this:
(parameters) -> expressionFor example:
() -> System.out.println("Hello, John!")The -> symbol is called the lambda operator.
A Simple Example
Let's say we want to create a small piece of code that prints a message.
Normally, we might create a method:
static void greet() {
System.out.println("Hello, John!");
}With a lambda expression, we can write:
() -> System.out.println("Hello, John!")The lambda itself doesn't have a name. It simply describes the action we want to perform.
Lambda with Parameters
A lambda expression can also accept parameters.
For example:
(name) -> System.out.println("Hello, " + name)Here, name is the parameter.
We can also have multiple parameters:
(a, b) -> a + bThis takes two values and returns their sum.
Lambda Expressions and Functional Interfaces
There is an important concept you need to understand before using lambdas properly.
A lambda expression is generally used with a functional interface.
A functional interface is an interface that has exactly one abstract method.
For example:
interface Calculator {
int calculate(int a, int b);
}Now we can use a lambda to provide the implementation:
Calculator add = (a, b) -> a + b;Here, the lambda:
(a, b) -> a + bprovides the implementation of the calculate() method.
We can then use it:
int result = add.calculate(10, 20);
System.out.println(result);Output:
30This is where lambda expressions become really useful.
Lambda with a Single Parameter
If a lambda has only one parameter, parentheses are optional.
For example:
name -> System.out.println("Hello, " + name)This is the same as:
(name) -> System.out.println("Hello, " + name)Both are valid.
Lambda with Multiple Statements
A lambda can contain multiple statements. When it does, we use curly braces.
(a, b) -> {
int result = a + b;
return result;
}For example:
Calculator add = (a, b) -> {
int result = a + b;
return result;
};The shorter version:
Calculator add = (a, b) -> a + b;does the same thing.
For simple operations, the shorter form is usually easier to read.
Lambda with ArrayList
Lambda expressions are frequently used with collections.
For example, suppose we have:
import java.util.ArrayList;
ArrayList<String> names = new ArrayList<>();
names.add("John");
names.add("Jason");
names.add("Alex");We can use forEach() with a lambda:
names.forEach(name -> System.out.println(name));Output:
John
Jason
AlexHere:
name -> System.out.println(name)means:
For each name in the list, print that name.
This is a very common use of lambda expressions.
Lambda with Sorting
Lambdas are also useful when sorting collections.
For example:
ArrayList<String> names = new ArrayList<>();
names.add("John");
names.add("Alex");
names.add("Jason");
names.sort((a, b) -> a.compareTo(b));This tells Java how to compare the two values when sorting the list.
After sorting, the names will be arranged alphabetically.
Lambda vs Traditional Method
Without a lambda, we might need to create an anonymous implementation:
Calculator add = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};That's quite a lot of code for such a simple operation.
With a lambda:
Calculator add = (a, b) -> a + b;Much shorter and easier to read.
This is one of the main reasons lambdas were introduced in Java.
Common Functional Interfaces
Java provides several useful functional interfaces in the java.util.function package.
Some commonly used ones are:
Predicate<T> — takes a value and returns true or false.
Predicate<Integer> isEven = number -> number % 2 == 0;Consumer<T> — takes a value and performs an action without returning a result.
Consumer<String> print = name -> System.out.println(name);Function<T, R> — takes one type of value and returns another type.
Function<Integer, Integer> square = number -> number * number;Supplier<T> — provides a value without taking an argument.
Supplier<String> message = () -> "Hello, John!";You don't need to memorize all of these immediately. The important thing for now is understanding that Java provides ready-made functional interfaces that work naturally with lambdas.
A Complete Example
Let's create a simple program using a lambda with an ArrayList:
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("John");
names.add("Jason");
names.add("Alex");
names.forEach(name -> {
System.out.println("Hello, " + name);
});
}
}Output:
Hello, John
Hello, Jason
Hello, AlexThe lambda tells forEach() what to do with each element.
The main thing to remember is:
A lambda expression is a short way of representing a piece of behavior, especially when working with functional interfaces and collections.
The basic syntax is:
(parameters) -> expressionOnce you understand lambdas, you'll start seeing them frequently in modern Java code, especially when working with collections, streams, and functional programming features.