Runnable::new vs new Runnable()
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);
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.
Compare two calls:
((Runnable)() -> new R()).run();new R().run();
By ((Runnable)() -> new R())
or ((Runnable) R::new)
, you create a new Runnable
which does nothing1.
By new R()
, you create an instance of the R
class where the run
method is well-defined.
1 Actually, it creates an object of R
which has no impact on execution.
I was thinking of treating 2 invocations identically without modifying the main
method. We would need to overload run(Runnable)
with run(Supplier<Runnable>)
.
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(); } void run(Supplier<Runnable> s) { run(s.get()); } static class R implements Runnable { ... }}