Runnable:: new vs new Runnable()

  • A+

Why doesn't the first of the following examples work?

  • run(R::new); method is not called.
  • run(new R()); method is called.

Both examples are compiled-able.

public class ConstructorRefVsNew {    public static void main(String[] args) {       new ConstructorRefVsNew().run(R::new);       System.out.println("-----------------------");       new ConstructorRefVsNew().run(new R());   }    void run(Runnable r) {;   }    static class R implements Runnable {        R() {           System.out.println("R constructor runs");       }        @Override       public void run() {           System.out.println(" runs");       }   } } 

The output is:

  R constructor runs   -----------------------   R constructor runs runs 

In the first example, the R constructor is called, it returns lambda (which is not object):

Runnable:: new vs new Runnable()

But then how is it possible, that the example is compiled successfully?


Your run method takes a Runnable instance, and that explains why run(new R()) works with the R implementation.

R::new is not equivalent to new R(). It can fit the signature of a Supplier<Runnable> (or similar functional interfaces), but R::new cannot be used as a Runnable implemented with your R class.

A version of your run method that can takeR::new could look like this (but this would be unnecessarily complex):

void run(Supplier<Runnable> r) {     r.get().run(); } 

Why does it compile?

Because the compiler can make a Runnable out of the constructor call, and that would be equivalent to this lambda expression version:

new ConstructorRefVsNew().run(() -> {     new R(); //discarded result, but this is the run() body }); 

The same applies to these statements:

Runnable runnable = () -> new R(); new ConstructorRefVsNew().run(runnable); Runnable runnable2 = R::new; new ConstructorRefVsNew().run(runnable2); 

But, as you can notice, the Runnable created with R::new does just call new R() in its run method body.

A valid use of a method reference to execute R#run could use an instance, like this (but you'd surely rather use the r instance directly, in this case):

R r = new R(); new ConstructorRefVsNew().run(r::run); 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: