I'll make it simple.
Why does the following code compile:
final int[] arr = { 1, 2, 3, 4 };
final Supplier<Integer> summer = () ->
{
int temp = 0;
for (int i : arr) { temp = i; }
return temp;
};
final int sum = summer.get();
But the following snippet doesn't?
final int[] arr = { 1, 2, 3, 4 };
final int sum = (() ->
{
int temp = 0;
for (int i : arr) { temp = i; }
return temp;
}).get();
Error message:
SupplierTest.java:8: error: lambda expression not expected here
final int sum = (() ->
^
1 error
error: compilation failed
CodePudding user response:
You need a target type to identify what class the lambda is implementing. Otherwise there's no way to know whether you're declaring a Supplier
or, say, a Callable
. But if you want to avoid the variable, you can use a cast instead:
final int[] arr = { 1, 2, 3, 4 };
final int sum = ((IntSupplier)() ->
{
int temp = 0;
for (int i : arr) { temp = i; }
return temp;
}).getAsInt();
That said, I hope this is a theoretical exercise. There's almost no reason to use this in real code.
CodePudding user response:
Lambda expressions are so-called poly-expressions, which means they sensitive to the context in which they appear.
Lambdas in Java have no type by itself and compiler always needs to infer their type based on either:
- Assignment context;
- Invocation context;
- Casting context.
Here's a quote from the Java Language Specification §15.27. Lambda Expressions
It is a compile-time error if a lambda expression occurs in a program in someplace other than an assignment context (§5.2), an invocation context (§5.3), or a casting context (§5.5).
Your first snippet is an example of a lambda expression which appear in the Assignment context, i.e. the type specified on the left tells what should be the target Functional interface to which this lambda conforms:
final Supplier<Integer> summer = () ->
{
int temp = 0;
for (int i : arr) { temp = i; }
return temp;
};
Meanwhile, in your second snippet, there's doesn't compile because there's no way to infer the type of the lambda expression.
An example of Casting context can be observed in the answer by @shmosel.
And here's an illustration of how target type can be provided through the Invocation context:
final int[] arr = {1, 2, 3, 4};
final int sum = foo(() -> {
int temp = 0;
for (int i : arr) temp = i;
return temp;
});
As foo()
you can use:
public static <T> T foo(Supplier<T> supplier) {
return supplier.get();
}
Or:
public static int get(IntSupplier supplier) {
return supplier.getAsInt();
}