Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does functional interface with void return-type method accept any return-type method? [duplicate]

We have this code:

public class Test {
    public static Object foo() {
        System.out.println("Foo");
        return new Object();
    }

    public static void main(String[] args) {
        J j = Test::foo;
        j.m();
    }

}
interface J {
    void m();
}

And this code will work. The crucial line is

J j = Test::foo;

Although interface J declares it has a void function, Test::foo returns an Object.

While we can't override method while implementing interface (which is obvious). This works only when interface's method is void, otherwise the code won't be compiled. Could someone tell why does this work in the way it works? :D

like image 976
Yevhenii Smyrnov Avatar asked Sep 27 '19 11:09

Yevhenii Smyrnov


2 Answers

Although interface J declares it has a void function, Test::foo returns an Object.

It's inaccurate to say that Test::foo returns something. In different contexts, it could mean different things.

Supplier<Object>  a = Test::foo;
J                 b = Test::foo;
Runnable          c = Test::foo;

It's more accurate to say that Test::foo can represent a target type the functional method of which returns either void or Object.

It's an example of expression statement (jls-14.8).

If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).
...
An expression statement is executed by evaluating the expression; if the expression has a value, the value is discarded.

like image 62
Andrew Tobilko Avatar answered Oct 03 '22 15:10

Andrew Tobilko


I am not sure what exactly is confusing you so here is some other way how you can look at your example.


J j = Test::foo;

can be rewritten as

J j = () -> Test.foo();

since it provides body to m() method from J functional interface and that method doesn't require any arguments (which is why it starts with () ->).

But that can be seen as shorter version of

J j = new J(){
    public void m(){
        Test.foo(); //correct despite `foo` returning value    
    }
};

which is correct, because Java allows us to ignore returned value of called method like in case of List#add(E element) which returns boolean value, but we still are allowed to write code like list.add(1) without having to handle returned value.

like image 40
Pshemo Avatar answered Oct 03 '22 15:10

Pshemo