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.function
package
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 var 2. 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
static
method 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
new
as 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() |