The syntax of a lambda is simple –
(parameters) -> expression (parameters) -> { statements; }
Runnable r1 = () -> System.out.println("Hello World"); // or Streams List winnersOfToursLessThan3500km = tdfWinners .stream() .filter(d -> d.getLengthKm() > 3500) // Separate out Tours less than 3500km .map(Winner::getName) // Get names of winners .collect(toList()); // Return a list
Key points are –
The key requirement for a lambda is that the interface it implements can only have a Single Abstract Method(SAM). However they can have any number of default and static methods
@FunctionalInterface is Optional, and enforces this rule by generating a compiler error –
Invalid '@FunctionalInterface' annotation; NotFunctionalInteface is not a functional interface
Java8 contains a number of useful interfaces in java.util.function –
Predicate - boolean test(T t) - True/False condition on t Consumer - void accept(T t) - Accepts t but returns no result Function- R apply(T t) - Takes t and returns an instance of R
Describes the signature of the Functional Interface –
Predicate - t -> boolean Consumer - t -> void Function - t -> R
String finalString = "final string"; String effectivelyFinalString = "effectively final string"; Runnable r = () -> { System.out.println("Hi im " + finalString); System.out.println("Hi im " + effectivelyFinalString); }; new Thread(r).start();
But trying to change effectivelyFinalString results stops it compiling –
String finalString = "final string"; String effectivelyFinalString = "effectively final string"; Runnable r = () -> { System.out.println("Hi im " + finalString); System.out.println("Hi im " + effectivelyFinalString); }; effectivelyFinalString = "now i wont compile"; new Thread(r).start();
The reason this works is that the lambda is accessing a copy of the final or “effectively final” field.
The final piece of the lambda jigsaw is Method References. Method references are simply a further shorthand in the body of the lambda – so where we have a lambda –
List winnersOfToursGreaterThan3500km = tdfWinners .stream() .filter(d -> d.getLengthKm() >= 3500) .map(w -> w.getName()) .collect(toList());
We see map has the lambda – w -> w.getName(). This represents this method –
Stream map(Function super T, ? extends R> mapper);
A method reference lets us shorthand that too –
List winnersOfToursGreaterThan3500km = tdfWinners .stream() .filter(d -> d.getLengthKm() >= 3500) .map(W::getName) .collect(toList());
As with a lot of Java8 the purpose of this shorthand is to allow us to write cleaner more concise code
There are 4 types of method reference in Java 8 –
static method | ContainingClass::staticMethodName |
instance method of a particular object | containingObject::instanceMethodName |
instance method of an arbitrary object of a particular type | ContainingType::methodName |
constructor | ClassName::new |