I'm reading a chapter on lambdas in Herbert Schildt's "Java: The Complete Reference" and there are quite a few references to "lambda target type" and "target type context":
A functional interface defines the target type of a lambda expression. Here is a key point: a lambda expression can be used only in a context in which its target type is specified.
Or:
As mentioned earlier, a lambda expression is not executed on its own. Rather, it forms the implementation of the abstract method defined by the functional interface that specifies its target type. As a result, a lambda expression can be specified only in a context in which a target type is defined. One of these contexts is created when a lambda expression is assigned to a functional interface reference. Other target type contexts include variable initialization, return statements, and method arguments, to name a few.
Yet another:
The functional interface associated with a lambda expression can be generic. In this case, the target type of the lambda expression is determined, in part, by the type argument or arguments specified when a functional interface reference is declared.
Can someone please help me understand what's meant by lambda target type?
For instance, in (int n) -> n % 2 == 0
is int
the lambda's target type?
Or in:
interface MyInterface<T> {
T func();
}
MyInterface<String> myInt = () -> { return "123"; }
What is the lambda's target type? Is it String
or MyInterface<String>
? And what is the lambda's context here?
I read several posts on SO on the topic but still cannot fully understand the notions.
Thanks.
Lambda Expressions do not have an explicit type. Their type is inferred by looking at the target type of the context or situation. The Target-Type of an expression is the data type that the Java Compiler expects depending on where the expression appears.
The Target-Type of an expression is the data type that the Java Compiler expects depending on where the expression appears. Java 8 supports inference using Target-Type in a method context.
The compiler infers the type of a lambda expression. The context in which a lambda expression is used expects a type, which is called the target type. The process of inferring the type of a lambda expression from the context is known as target typing.
By now you may have guessed that resolving this error " the target type of this expression must be a functional interface " means functional interface should have only one abstract method. So we need to delete the second method.
I decided to read a bit more about lamdas and found an excellent book "Beginning Java 8 Language Features: Lambda Expressions, Inner Classes, Threads, I/O, Collections and Streams" by Kishori Shiran.
I will just cite a few paragraphs:
Every expression in Java has a type; so does a lambda expression. The type of a lambda expression is a functional interface type. When the abstract method of the functional interface is called, the body of the lambda expression is executed.
Consider the lambda expression that takes a String parameter and returns its length:
(String str) -> str.length()
What is the type of this lambda expression? The answer is that we do not know. By looking at the lambda expression, all you can say is that it takes a String parameter and returns an int, which is the length of the String. Its type can be any functional interface type with an abstract method that takes a String as a parameter and returns an int. The following is an example of such a functional interface:
@FunctionalInterface
interface StringToIntMapper {
int map(String str);
}
The lambda expression represents an instance of the
StringToIntMapper
functional interface when it appears in the assignment statement, like so:
StringToIntMapper mapper = (String str) -> str.length();
In this statement, the compiler finds that the right-hand side of the assignment operator is a lambda expression. To infer its type, it looks at the left-hand side of the assignment operator that expects an instance of the
StringToIntMapper
interface; it verifies that the lambda expression conforms to the declaration of themap()
method in theStringToIntMapper
interface; finally, it infers that the type of the lambda expression is theStringToIntMapper
interface type.This lambda expression may be of different functional interface types depending on the context in which it is used. There are two types of expressions in Java - standalone expressions and poly expressions
A standalone expression is an expression whose type can be determined by the expression without knowing the context of its use. A poly expression is an expression that has different types in different contexts. The compiler determines the type of the expression. The contexts that allow the use of poly expressions are known as poly contexts. All lambda expressions in Java are poly expressions. You must use it in a context to know its type. Poly expressions existed in Java prior to Java 8 and lambda expressions. For example, the expression
new ArrayList<>()
is a poly expression. You cannot tell its type unless you provide the context of its use.The compiler infers the type of a lambda expression. The context in which a lambda expression is used expects a type, which is called the target type. The process of inferring the type of a lambda expression from the context is known as target typing. Consider the following pseudo code for an assignment statement where a variable of type
T
is assigned a lambda expression:
T t = <LambdaExpression>;
The target type of the lambda expression in this context is
T
. The compiler uses the following rules to determine whether the<LambdaExpression>
is assignment compatible with its target typeT
:
T
must be a functional interface type.- The lambda expression has the same number and type of parameters as the abstract method of
T
. For an implicit lambda expression, the compiler will infer the types of parameters from the abstract method ofT
.- The type of the returned value from the body of the lambda expression is assignment compatible to the return type of the abstract method of
T
.- If the body of the lambda expression throws any checked exceptions, those exceptions must be compatible with the declared throws clause of the abstract method of
T
. It is a compile-time error to throw checked exceptions from the body of a lambda expression, if its target type's method does not contain a throws clause.
One of the definitions of "target" (taken from here) is:
a result or situation that you intend to achieve.
You can say the result a lambda expression intends to achieve is to implement some functional interface. Hence that functional interface can be seen as the target of that lambda expression, and the type of the functional interface is the target type.
Hence the target type is the type of the functional interface implemented by the lambda expression.
The target type can be inferred based on the context in which the lambda expression is used:
In
(int n) -> n % 2 == 0
the target type is unknown. If you assign this expression to some functional interface reference, that would be the target type.
In
MyInterface<String> myInt = () -> { return "123"; }
the target type is MyInterface<String>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With