Another Java Lambda Post: Functional Interfaces
This in-depth look at Java lambdas focus on the functional interface and the ability to have a SAM (single abstract method) in your interfaces.
Join the DZone community and get the full member experience.
Join For FreeI held back writing this post because I felt the last thing the Java world needs is another Lambda post, but the main reason I blog is to improve my ability to explain technologies, so I decided to do it anyway.
The syntax of a lambda is simple:
(parameters) -> expression (parameters) -> { statements; }
Examples
Runnable r1 = () -> System.out.println("Hello World");
// or Streams
List<String> 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:
- Concise: Before Java 8, we would use anonymous classes to deliver “similar” functionality.
- Anonymous: no explicit name.
- Function: not associated with a particular class.
- Argument: can be passed as an argument or stored in a variable.
Functional Interfaces
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 Annotation
@FunctionalInterface is Optional and enforces this rule by generating a compiler error:
Invalid '@FunctionalInterface' annotation;
NotFunctionalInteface is not a functional interface
Java 8 contains a number of useful interfaces in java.util.function:
Predicate<T>
- boolean test(T t)
- True/False condition on t
Consumer<T>
- void accept(T t)
- Accepts t but returns no result
Function<T, R>
- R apply(T t)
- Takes t and returns an instance of R
Functional Descriptor
Describes the signature of the Functional Interface:
Predicate - t -> boolean Consumer - t -> void Function - t -> R
Accessing Class Variables
Final or “effectively final”(not changed after initialization)
final 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 from 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.
Published at DZone with permission of Martin Farrell, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments