Lambda
- A lambda expression can be thought of as implicit code for an anonymous class, using a special kind of interface, as the mechanics to do this
- The method reference goes even further, and is a shortcut for the lambda expression syntax, for existing methods
The Lambda Expressionโ
| Lambda Expression | Comparatorโs Abstract Method |
|---|---|
(o1, o2) -> o1.lastName().compareTo(o2.lastName()) | int compare(T o1, T o2) |
- The lambda expression parameters are determined by the associated interface's method, the functional method
- A lambda expression consists of a formal parameter list, usually but not always declared in parentheses; the arrow token; and either an expression or a code block after the arrow token
- The expression should return a value, if the associated interface's method returns a value
Anonymous class and the lambda expressionโ
Anonymous Classโ
new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.lastName().compareTo(o2.lastName());
}
}
Lambda Expressionโ
(o1,o2)->o1.lastName().compareTo(o2.lastName());
- Lambda expression has no reference to an enclosing method, the method is inferred by Java
- Java requires types which support lambda expressions, to be something called a functional interface
- A functional interface is an interface that has one, and only one, abstract method
- A functional interface is the target type for a lambda expression
Lambda expression variationsโ
For a single parameterโ
| Lambda Expression | Description |
|---|---|
element -> System.out.println(element); | A single parameter without a type can omit the parentheses |
(element) -> System.out.println(element); | Parentheses are optional |
(String element) -> System.out.println(element); | Parentheses required if a reference type is specified |
(var element) -> System.out.println(element); | A reference type can be var |
The lambda bodyโ
Single expressionโ
element ->System.out.println(element);
Code blockโ
element -> {
char first = element.chartAt(0);
System.out.println(element + " means " + first);
};
With multiple parametersโ
| Lambda Expression | Description |
|---|---|
(a, b) -> a + b; | Parentheses are always required. Explicit types are not |
(Integer a, Integer b) -> a + b; | If you use an explicit type for one parameter, you must use explicit types for all the parameters |
(var a, var b) -> a + b; | If you use var for one parameter, you must use var for all parameters |
The lambda bodyโ
Single expressionโ
(a,b) -> a +b;
Code blockโ
(a,b) -> {
var c = a + b;
return c;
};
java.util.functionโ
- Java provides a library of functional interfaces in the
java.util.functionpackage
Basic categories of Functional Interfacesโ
| Interface Category | Basic Method Signature | Purpose |
|---|---|---|
Consumer | void accept(T t) | execute code without returning data |
Function | R apply(T t) | return a result of an operation or function |
Predicate | boolean test(T t) | test if a condition is true or false |
Supplier | T get() | return an instance of something |
The Consumer interfaceโ
The two most common:
| Interface Name | Method Signature |
|---|---|
Consumer | void accept(T t) |
BiConsumer | void accept(T t, U u) |
Example:
s -> System.out.println(s)
The Predicate Interfaceโ
The two most common:
| Interface Name | Method Signature |
|---|---|
Predicate | boolean test(T t) |
BiPredicate | boolean test(T t, U u) |
Example:
s -> s.equalsIgnoreCase("Hello")
The Function Interfaceโ
The four most common:
| Interface Name | Method Signature |
|---|---|
Function<T, R> | R apply(T t) |
BiFunction<T, U, R> | R apply(T t, U u) |
UnaryOperator<T> | T apply(T t) |
BinaryOperator<T> | T apply (T t1, T t2) |
Example:
Function<String, String[]> function = s -> s.split(",")
The Supplier Interfaceโ
Takes no argument, but lambda expressions can use final or effectively final variables in their expressions
Example:
() -> random.nextInt(1,100)
Valid Lambda Declarationsโ
| Arguments in Functional Method | Valid lambda syntax |
|---|---|
| None | () -> statement |
| One | s -> statement(s) -> statement(var s) -> statement(String s) -> statement |
| Two 1. When using var, all arguments must use var2. When specifying explicit types, all arguments must specify explicit types | (s, t) -> statement(var s, var t) -> statement(String s, List t) -> statement |
Method Referenceโ
- Methods which can be used, are based on the context of the lambda expression
- This means the method reference, is again dependent on the targeted interface's method
- We can reference a
staticmethod on a class - We can reference an instance method from either an instance external to the expression, or an instance passed as one of the arguments
- Or you can reference a constructor, by using
newas the method
| Lambda Expression | Method Reference |
|---|---|
s -> System.out.println(s) | System.out::println |
Deferred Method Invocationโ
- When you create variables that are lambda expressions or method references, it's important to remember that the code isn't invoked at that point
- The statement or code block gets invoked at the point in the code that the targeted functional method is called
For static methodsโ
Integer::sum
For a Bounded Receiverโ
An instance derived from the enclosing code, used in the lambda expression, on which the method will be invoked
System.out::println
For an Unbounded Receiverโ
The first argument becomes the instance used, on which the method gets invoked
String::concat
| Type | Syntax | Method Reference Example | Corresponding Lambda Expression |
|---|---|---|---|
| static method | ClassName::staticMethodName(p1, p2, ... pn) | Integer::sum | (p1, p2) -> p1 + p2 |
| instance method of a particular (Bounded) object | ContainingObject::instanceMethodName(p1, p2, ... pn) | System.out::println | p1 -> System.out.println(p1) |
| instance method of an arbitrary (Unbounded) object (as determined by p1) | ContainingType[=p1]::instanceMethodName(p2, ... pn) | String::concat | (p1, p2) -> p1.concat(p2) |
| constructor | ClassName::new | Player::new | () -> new Player() |
Convenience Methodsโ
| Category of Interface | Convenience method example | Notes |
|---|---|---|
Function | function1.andThen(function2) | Not implemented on IntFunction, DoubleFunction, LongFunction |
Function | function2.compose(function1) | Only implemented on Function & UnaryOperator |
Consumer | consumer1.andThen(consumer2) | |
Predicate | predicate1.and(predicate2) | |
Predicate | predicate1.or(predicate2) | |
Predicate | predicate1.negate() |
Comparator's additional helper methodsโ
| Type of Method | Method Signature |
|---|---|
static | Comparator comparing(Function keyExtractor) |
static | Comparator naturalOrder() |
static | Comparator reverseOrder() |
default | Comparator thenComparing(Comparator other) |
default | Comparator thenComparing(Function keyExtractor) |
default | Comparator reversed() |