0

I have this piece of code

public <T> someMethod(Supplier<T> supplier) {
        Objects.requireNonNull(supplier);
        SupplierThrowsException<T, Throwable> supplierThrowsException = supplier::get;
        return withThrowable(supplierThrowsException);
}

I am calling it like this

obj.someMethod(() -> myMethod(message))

I am 100% sure that the class of the object returned by myMethod() does not implement Supplier interface. So where is the implementation of get().

I went through the Javadoc, I didn't get anything. I would like to understand what's going on here.

I found this and this but it doesn't clear my doubt. Let me know if I am missing anything here.

raviiii1
  • 936
  • 8
  • 24
  • 3
    You need to understand how lambda expressions work (and *functional* interfaces). It's the lambda expression `() -> myMethod(message)` that implements `Supplier.get` – ernest_k Apr 23 '19 at 08:19
  • Is there any Interface for lambdas in java? Could you point out some docs, articles or posts that would explain this? – raviiii1 Apr 23 '19 at 08:20
  • Here's a good place to start: [Why do I need a functional Interface to work with lambdas?](https://stackoverflow.com/questions/33010594/why-do-i-need-a-functional-interface-to-work-with-lambdas) – ernest_k Apr 23 '19 at 08:23
  • 2
    @raviiii1 try implementing the anonymous class representation of the lambda and things would be much clearer to understand and correlate them. – Naman Apr 23 '19 at 08:23
  • @ernest_k, if the expression () -> `myMethod(message)` implements Supplier.get, then how does it return SupplierThrowsException in the example? – raviiii1 Apr 23 '19 at 08:29
  • 1
    @raviiii1 It returns the result of calling `withThrowable(supplierThrowsException)`, and that is NOT `SupplierThrowsException`. I'd guess that the return type of `withThrowable` is `T` (the same `T` as returned by `supplier`) – ernest_k Apr 23 '19 at 08:32

4 Answers4

3

In this call:

obj.someMethod(() -> myMethod(message))

you are implementing the Supplier interface using a lambda expression - () -> myMethod(message).

It is as if (I say "as if" because this is not what actually happens under the hood. Here is what happens under the hood) you have created an inner class implementing Supplier like this:

static class MyInnerClass implements Supplier<SomeClass> {
    public SomeClass get() {
        return myMethod(message);
    }
}

And then passed new MyInnerClass() to someMethod.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
3

I am 100% sure that the class of the object returned by myMethod() does not implement Supplier interface.

Sure, but the expression () -> myMethod(message) does.

Please, read 15.27.4. Run-Time Evaluation of Lambda Expressions.

At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.

Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.

The value of a lambda expression is a reference to an instance of a class with the following properties:

  • The class implements the targeted functional interface type and, if the target type is an intersection type, every other interface type mentioned in the intersection.

In short, the lambda expression () -> myMethod(message) will be resolved to an instance of Supplier.

Where is the implementation of get()?

You've provided it within the lambda body.

() -> myMethod(message) 

(it's a statement expression, a shorter form to construct a lambda body)

() -> {
    return myMethod();
}

(it's a value-compatible block, a more expanded version where many statements may be declared)

Community
  • 1
  • 1
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
1

I think this document may shed some light on your question: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#target-typing

To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type:

Variable declarations

Assignments

Return statements

Array initializers

Method or constructor arguments

Lambda expression bodies

Conditional expressions, ?:

Cast expressions

Community
  • 1
  • 1
mate00
  • 2,727
  • 5
  • 26
  • 34
1

Supplier is a functional interface and contains following single abstract method:

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

Now, you have provided definition of get method along with instantiation with following invocation:

obj.someMethod(() -> myMethod(message))

Above line gets translated as follows:

obj.someMethod(new Supplier() {

@Override
public T get() 
{ 
  return myMethod(message);
}

});
Anshul Singhal
  • 1,983
  • 20
  • 25