Introduction to Java 8 lambdas
In today’s TL;DR series, we’ll talk about lambdas. Click here to know more about the TL;DR series.
Java lambdas are the first step into making Java methods a first-class-citizen. If it achieves this as of Java 8 is a debate left for another time. But lambdas do achieve the following:
- They are anonymous, you do not need to define them in a named file or class.
- Can be assigned to a variable and stored in data structures.
- Passed to methods as arguments.
- Returned from methods.
Lambda’s are not a class on their own (a type), instead, lambda’s are instantiated as a sub-type of a special subset of interfaces called functional interfaces. These classes are refereed as the lambda’s target type.
Functional interfaces are interfaces with exactly one abstract method. The @ FunctionalInterface annotation causes the compiler to enforce this check but it is not required.
A lambda is the implementation for the abstract method in a functional interface. Java uses the arrow operator (->) to denote the creation of a lambda expression. The left side defines the parameters required for the lambda expression. The right side contains the lambda’s body.
To invoke the lambda, execute target type’s single method.
Basic Lambda Syntax Properties
Passed as Arguments
List.forEach() accepts a Consumer (a functional interface) as an argument.
Target Type
The type of a lambda is determined by the compiler based its target type. This means the same lambda expression can be assigned different types so long as their arguments and return types match.
Because the lambda’s are different types, you cannot pass one lambda for the other.
Lamdas Are Like Closures
When the run() method is executed, the output is “I’m from the parent scope”.
- Members declared inside the expression are private to the expression.
- The expression has access to members from the parent scope, even after the parent method context finishes. Parent variables accessed from the lambda are not garbage collected as the lambda still has a reference to it.
But There Are Differences
With JavaScript closures, variables used within the closure from the parent scope are resolved when the closures is invoked. Java lambdas are different. Variables used within a lambda are effectively treated as if declared final. They cannot be assigned another value after being assigned one. This is enforced though compile-time validations.
Even though variables cannot be assigned new values, the values themselves can be mutable. In JavaScript, closures “close over variables”, which are resolved at closure invocation time. Java lambda’s “close over values, not variables”.
In JavaScript, we might think the output is 3 3 3 because the variable j is “closed over” and resolved at invocation time. In Java, the value of j is set at expression creation time thus the output is 1, 2, 3
In this case, the output is 2 2 2 because we are updating the same IntWrapper instance each iteration. The wrapper variable is not getting reassigned so we maintain its “final” like assignment. Remember: final does not mean the object assigned to the variable is non-mutable.
That’s my basic short introduction of lambdas. Java 8 also introduces method references, which is a related subject, but we’ll leave that topic for another time.
I love to hear any feedback or if there was something something I missed. Leave a comment below!