Describe a lambda expression; refactor the code that uses an anonymous inner class to use a lambda expression; describe type inference and target typing.
Lambda expressions are similar to anonymous classes, but only have the implementation of the methods. Therefore, they are like "anonymous methods" that can be passed via variables.
Understanding lambda functions, and variations in their syntax, is essential to understanding the next sections of Built-in Interfaces and Method References.
The lambda expression has 3 parts:
-
A comma-separated list of parameters
-
Sometimes has parentheses
-
Sometimes has variable type
-
-
The "arrow token", which is always written as
-> -
A body, which may or may not be enclosed in braces
-
Can have more than one line
-
Sometimes has a
return -
Sometimes has semicolon
-
Examples of lambda expressions:
-
i → System.out.println(i) -
(Integer i) → System.out.println(i) -
(Integer i) → { System.out.println(i); } -
(Integer i) → { return i + 1; } -
(i, j, k) → { return i + j + k; } -
(i, j, k) → System.out.println(i + j + k) -
() → System.out.println("nothing")
-
Lambda expressions can be understood as a different way of declaring anonymous classes.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AnonymousClass.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AnonymousClass.java[role=include]
Note that in the example above a
Threadis instantiated with an anonymous instance ofRunnable. In the second part, the same thing is done much simpler using a lambda expression. -
Lambda expressions are always used to create instances of functional interfaces, i.e., interfaces that have only a single abstract method.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_FunctionalInterface.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_FunctionalInterface.java[role=include]
console outputperformed with anonymous class performed with lambda expression
Note that in the example above the same
executeAndPresentMessagemethod is invoked twice. The first time a new anonymous class is passed. The second time a lambda expression is passed.Also see that it would be impossible to create a lambda expression if the interface was not functional, i.e., it had more than one abstract method. The compiler would not be able to identify that the
executemethod of the` Executable` interface is being implemented within the lambda expression. -
There are many methods already available in Java 8 that benefit from lambda expression syntax, such as
forEachlists.src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_ForEach.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_ForEach.java[role=include]
console output1 2 3 4 5
Note that the new
forEachmethod executes the lambda expression passed as a parameter to each list item, printing them all to the console. The lambda expression takes as a parameter a number, which is the list number.In this case, the functional interface being implemented by the lambda expression is called
Consumer. It will be explained in detail in a later section, along with other standard Java 8 functional interfaces. In this section, it is essential to understand what lambda expressions are and what their syntax is like. -
Declarations of lambda expressions can be complete or simplified.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_SimpleComplete.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_SimpleComplete.java[role=include]
The two lambda functions above are identical, but one is more explicit than the other.
-
Parentheses can only be omitted if there is no type declaration, and there is only a single argument.
-
Lambda expressions that do NOT have arguments also need parentheses.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Parenthesis.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Parenthesis.java[role=include]
-
The use of curly brackets, semicolons and
return(if the function returns any value) is required in lambda expressions with more than one line.src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Block.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Block.java[role=include]
-
When making the type of one of the arguments explicit, it is mandatory to inform all of them.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_VarType.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_VarType.java[role=include]
-
It is not allowed to declare variables with the same name within the lambda expression.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Shadowing.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Shadowing.java[role=include]
-
It is allowed to access external variables within the lambda expression, but only final variables or variables that do not change.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AccessExternalVar.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_AccessExternalVar.java[role=include]
Note that the compiler identifies that the
x3variable is changed at the end of the method, and therefore does not allow it to be used in the lambda expression. -
In ambiguous situations, the compiler tries to find out the type of lambda expression using the context.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_TypeInference.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_TypeInference.java[role=include]
In the previous example, only the
runmethod of theApplicationfunctional interface returns aString, while theexecutemethod of theExecutablefunctional interface returns nothing (void). This is enough difference for the compiler to know which method to call each timedoThisis invoked.On the first call to the
doThismethod, since the passed lambda expression returns aString, the compiler understands that this lambda expression is an implementation of theApplicationinterface, as therunmethod also returns aString.On the second call to the
doThismethod, since the lambda expression returns nothing (just prints theString"executing"), the compiler understands that this lambda expression is an implementation of theExecutableinterface, because theexecutealso returns nothing. -
If the type of the lambda expression cannot be found, a compilation error occurs.
src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Ambiguity.javalink:../../../src/org/j6toj8/lambda/lambdaexpression/LambdaExpression_Ambiguity.java[role=include]
In the previous example, because both functional interfaces have a
voidmethod, the compiler does not know which one is being instantiated in the lambda expression, and a compilation error occurs. The lambda expression in this example could be eitherPilotorRunner, and there is no way for the compiler to find out which developer actually wanted to use it.
-
Implementing Functional Interfaces with Lambdas
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 55). Wiley. Kindle Edition.
-
Using Variables in Lambdas
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 172). Wiley. Edição do Kindle.
-
Lambda Expressions and Functional Interfaces: Tips and Best Practices.
-
Lambda Expressions. The Java™ Tutorials.