Lambda is a language feature introduced since Java SE 8, it is a concise expression to represent a block of code that takes in parameters and returns a value. Lambda expressions are similar to methods but they do not need a name and can be implemented right in the body of a method.
Note
Lambda expression cannot contain variables, assignments or statements such as
if
orfor
.
Basic syntax
(parameter_list) -> { body }
parameter_list
is a comma-separated list of parameters that the lambda expression can accept. The parameter list can be zero parameter or more parameters. In most cases you can omit the type of parameter in a lambda expression when the compiler can infer it from the context using type inference.
->
is an lambda operator divides the parameter list from the body of expression.
{ body }
is the code block that gets executed when the lambda expression is invoked, it can contain one or more statements.
(int a, int b) -> { return a + b; }
This example is a simple lambda expression that represents a function that adds two numbers.
Lambda with functional interfaces
Lambda expressions are often used with functional interfaces which are interfaces with a Single Abstract Method (SAM). You can think of a lambda expression as an implementation of that SAM.
Example 1 - Without lambda
The below code implements the functional interface using anonymous nested class.
@FunctionalInterface
interface Addable {
void add(int a, int b);
}
public class Demo {
public static void main(String[] args) {
int a = 10;
int b = 20;
Addable ad = new Addable() {
public void add(int x, int y) {
System.out.println(x + y);
}
};
ad.add(a, b);
}
}
Using lambda expression Now we rewrite the program using lambda expression.
public class Demo {
public static void main(String[] args) {
int a = 10;
int b = 20;
// use lambda to implement the add method
Addable ad = (x, y) -> System.out.println(x + y);
ad.add(a, b);
}
}
30
To improve clarity, you can add curly braces and parameter type.
public class Demo {
public static void main(String[] args) {
int a = 10;
int b = 20;
// add parameter type and enclose expression body with braces
Addable ad = (int x, int y) -> {
System.out.println(x + y);
};
ad.add(a, b);
}
}
30
Example 2 - Lambda with return
Lambda expression can have return values. Single line lambda statement without return keyword:
@FunctionalInterface
interface Addable {
int add(int a, int b);
}
public static void main(String[] args) {
int a = 10;
int b = 20;
Addable ad = (x, y) -> x+y;
System.out.println(ad.add(10, 20));
}
Multiple line lambda statements with return keyword:
public static void main(String[] args) {
int a = 10;
int b = 20;
Addable ad = (x, y) -> {
return x+y;
};
System.out.println(ad.add(10, 20));
}
Example 3
Lambda also works with functional interfaces in the Java Standard Library such as Runnable
, Predictate
and Consumer
, and is used extensively in Stream API.
The lambda can work with forEach
method which is a part of Java stream API and takes a functional interface called Consumer
.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach(n -> System.out.println(n));
Here the forEach
is called on numbers
list, it takes the lambda expression as its argument.
Lambda expression and its parameter
The lambda expression is an implementation of Consumer
interface, the (n -> System.out.println(n))
represents a anonymous Consumer<Integer>
object, since parameter n
is inferred as Integer.
Expression body
The only abstract method of Consumer accpept
is implemented by taking the parameter n
and its body System.out.println(n)
.
Without using lambda expression, you typically use anonymous nested class:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Consumer<Integer> printConsumer = new Consumer<Integer>() {
@Override
public void accept(Integer n) {
System.out.println(n);
}
};
// use forEach with the created Consumer
numbers.forEach(printConsumer);
The forEach
method takes each element (integer) from the list and assigns it to the variable n
, and then it performs the action specified.
More examples are available in For each.
Method reference
A method reference is a shorthand notation of a lambda expression that executes a specific method. It provides a cleaner, more readable way to refer to methods or constructors directly using the ::
operator.
There are different kinds of method reference:
Kind | Syntax | Example | Lambda expression |
---|---|---|---|
Reference to a static method | ClassName::staticMethodName | String::valueOf | s -> String.valueOf(s) |
Reference to an instance method of a particular object | instance::instanceMethodName | s::toString | s -> s.toString() |
Reference to instance method of an arbitrary object of a given type | ClassName::instanceMethodName | String::toString | s -> s.toString() |
Reference to a contructor | ClassName::new | String:new | () -> new String() |
Reference to a static method
Syntax: ClassName::staticMethodName
In this example we use comparator to sort a string array. Here is the implementation using classic lambda expression.
public class Demo {
public static void main(String[] args) {
String[] nameArray = {"Barbara", "James", "Mary", "John"};
Arrays.sort(nameArray, (s, t) -> s.compareToIgnoreCase(t));
}
}
We can simplify the expression using String
class’s compareToIgnoreCase
static method as a method reference.
Tip
One good aspect of method reference is that it promotes code reuse and it works well with strategy pattern. You can just change the parameters to achieve different sorting strategy. In this case we can replace the
compareToIgnoreCase
withcompareTo
to suite different needs.
public class Demo {
public static void main(String[] args) {
String[] nameArray = {"Barbara", "James", "Mary", "John"};
Arrays.sort(nameArray, String::compareToIgnoreCase);
}
}
Reference to a constructor
This example uses stream and its map()
method to convert names in nameArray
into a list of Person
objects.
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class Demo {
public static void main(String[] args) {
String[] nameArray = {"Barbara", "James", "Mary", "John"};
List<Person> students = new ArrayList<>();
students = nameArray.stream()
.map(name -> new Student(name))
.toList();
}
}
We can rewrite this lambda expression using method reference.
public class Demo {
public static void main(String[] args) {
String[] nameArray = {"Barbara", "James", "Mary", "John"};
List<Person> students = new ArrayList<>();
students = nameArray.stream()
.map(Person::new)
.toList();
}
}
Back to parent page: Java Standard Edition (Java SE) and Java Programming
Web_and_App_Development Programming_Languages Java Lambda_Expression Functional_Interface Anonymous_Nested_Class Method_Reference