Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runnable::new vs new Runnable()

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

  • run(R::new); method R.run is not called.
  • run(new R()); method R.run 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) {
      r.run();
  }

  static class R implements Runnable {

      R() {
          System.out.println("R constructor runs");
      }

      @Override
      public void run() {
          System.out.println("R.run runs");
      }
  }
}

The output is:

  R constructor runs
  -----------------------
  R constructor runs
  R.run runs

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

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

like image 414
user1722245 Avatar asked Jan 07 '19 10:01

user1722245


People also ask

What is new runnable ()?

lang. Runnable is an interface that is to be implemented by a class whose instances are intended to be executed by a thread. There are two ways to start a new Thread – Subclass Thread and implement Runnable. There is no need of subclassing a Thread when a task can be done by overriding only run() method of Runnable.

Does a new runnable create a new thread?

No. new Runnable does not create second Thread .

What is the difference between start () and run () method of thread class?

start method of thread class is implemented as when it is called a new Thread is created and code inside run() method is executed in that new Thread. While if run method is executed directly than no new Thread is created and code inside run() will execute on current Thread and no multi-threading will take place.


2 Answers

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);
like image 100
ernest_k Avatar answered Oct 16 '22 17:10

ernest_k


The first example:

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

is more or less equivalent to:

new ConstructorRefVsNew().run( () -> {new R();} );

The effect is you just create an instance of R but do not call its run method.

like image 24
Henry Avatar answered Oct 16 '22 17:10

Henry