Home > Enterprise >  Unable to invoke get() on a Supplier represented as a Lambda Expression
Unable to invoke get() on a Supplier represented as a Lambda Expression

Time:11-13

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();
}
  • Related