Java Programming/Lambda expressions
Introduction
editLambda expressions were introduced in Java 8 as a concise way to describe a piece of functionality as a first class member of the language. While the principle is similar to the use of anonymous inner classes to satisfy interfaces, lambda expressions make the code much more legible.
I.e., instead of
Collection<Book> results = library.findAll(new Predicate() {
@Override
public boolean test(Book book) {
return book.getTitle().contains("Java");
}
});
we can say simply:
Collection<Book> results = library.findAll(book -> book.getTitle().contains("Java"));
Syntax
editA lambda expression consists of two parts separated by the ->
characters, referred to as an "arrow":
Parameters -> Body
Parameters
editThe Parameters define the inputs to the expression. Generally, the Parameters are a comma-separated list of types and identifiers surrounded by parentheses:
( Type1 identifier1 , Type2 identifier2 ) -> Body
However, the types are often inferable from the context and can be omitted:
( identifier1, identifier2 ) -> Body
And also, if there is exactly one input and its type is inferable, the parentheses can be omitted:
identifier1 -> Body
Body
editThe body of the lambda expression describes what should be done with those inputs (if any). In general, the body is a block like any other:
Parameters -> { statements; ... return statement; }
The return statement can be omitted for expressions that simply operate on the inputs.
Parameters -> { statements; ... }
If the body consists only of a single statement, the braces and terminal semi-colon can be omitted:
Parameters -> statement
If the expression consists of a single return statement, the braces, return keyword, and terminal semi-colon can all be omitted:
Parameters -> result
Terminology
editThe java.util.function namespace contains many structures out-of-the-box, introducing some standard terminology falling under 3 broad types:
- "Functions": real functions in the mathematical sense, taking exactly one input and providing exactly one output;
- "Consumers": entities that accept inputs but do not provide any output (in the conventional sense); and
- "Suppliers": entities that provide a value every time it is invoked without requiring any input.
Interface | Inputs | Result | Signature | |
---|---|---|---|---|
Function<T, R>
|
T
|
R
|
T -> R
|
Accepts one input of type T and returns something of type R
|
Consumer<T>
|
T
|
T ->
|
Accepts one input of type T and does not return anything (void )
| |
Supplier<R>
|
R
|
-> R
|
Does not accept any inputs and returns objects of type R
|
Function and Consumer also have "Bi" variants accepting two inputs:
Interface | Inputs | Result | Signature | |
---|---|---|---|---|
BiFunction<S, T, R>
|
S, T
|
R
|
(S, T) -> R
|
Accepts two inputs, one of type S and another of type T , and returns something of type R
|
BiConsumer<S, T>
|
S, T
|
(S, T) ->
|
Accepts two inputs, one of type S and another of type T and does not return anything (void )
|
Further Reading
edit- Streams/Collections
- Functional Interfaces
- Method references