In the previous Lesson, we reduced our code to the following:
Button btn = new Button();
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
While this is relatively short, it still contains a lot of redundant information. The compiler already knows what kind of parameter it’s looking for, so we could theoretically get rid of the class name. Additionally, we are only overriding one method, so the compiler theoretically doesn’t need to know the name of the method we are overriding because there is only one choice.
To address this issue, Java 8 added lambda expressions.
With a lambda expression, we can reduce our code to the following:
Button btn = new Button();
btn.setOnAction( (ActionEvent event) -> { System.out.println("Hello World!"); } );
We have effectively created an unnamed EventHandler and overridden its unnamed handle(ActionEvent event) method. A lambda expression is essentially an unnamed method replacement for a class that has only one method.
Syntax The general syntax of a lambda expression is:
(param1,param2,...) -> {
statement1;
statement2;
return objectOfTheRightType;
}
If the method being called has only one parameter, you can omit the ( ):
param1 -> {
statement1;
statement2;
return objectOfTheRightType;
}
If the method being called has only one statement, you can omit the { }:
param1 -> statement1;
This leaves our code in the following form:
Button btn = new Button();
btn.setOnAction(event -> System.out.println("Hello World!"));
Which is often just written as:
btn.setOnAction(e -> System.out.println("Hello World!"));
A functional interface is an interface with exactly one abstract method.
If a class implements one or more functional interfaces, you can use a lambda expression to create an instance of the class and override the single method in question. Java will always be able to figure out which method you mean by its signature.
Let’s say you wanted to sort a list, named list, of strings by length then by lexicography. The appropriate API method is
Collections.sort(List<T> , Comparator<? super T>)
You could use an anonymous class:
Collections.sort(list,new Comparator<String>(){
@Override
public int compare(String s1, String s1) {
if(s1.length() != s2.length())
return s1.length() - s2.length();
else
return s1.compareTo(s2);
});
However, a lambda expression will simplify the syntax.
An equivalent lambda expression is:
Collections.sort(list,new Comparator<String>(){Collections.sort(list,(
String s1, String s2)->
{
if(s1.length() != s2.length())
return s1.length() - s2.length();
else
return s1.compareTo(s2);
}
Here's the same statement in compact form:
Collections.sort(list, (s1, s2) ->
s1.length() != s2.length()) ? s1.length() - s2.length() : s1.compareTo(s2));
Double colon Notation
Ex. 1 The Stream.filter(Predicate) method takes the elements of a stream and filters out elements that don’t match the predicate’s method (a Predicate takes in one Object parameter and returns a boolean). Let’s say we wanted to filter out all the null elements.
The appropriate method is Object.isNotNull(Object), so we write:
stream.filter(e -> Object.isNotNull(e));
However, the compiler already knows it’s looking for a method that takes an object and returns a boolean, as isNotNull(Object) already does. This allows us to use functional notation and just let the compiler fill in the rest:
stream.filter(Object::isNotNull);
Ex. 2
The :: operator can also be used to reference a constructor. The method ollectors.toCollection(Supplier<? extends Collection>
method requires a Supplier, which takes no parameters and returns a collection.
Using a lambda expression:
Collectors.toCollection(() -> new ArrayList());
Using functional notation:
Collectors.toCollection(ArrayList::new);
Last modified: March 09, 2023
Back to Anonymous Classes