Just my two cents here to give a more readable answer, for people are new to java lambda world.
What's this
R::new
is using method reference
, which emerged from java8, let you reuse existing method definitions and pass them just like lambdas. So when you write Runnable::new
, actually it means () -> new R()
, the result is a lambda;
new R()
is calling the constructor of class R
, and return an instance of that class, the result is a instance of R
.
We are now clear about what are them, but how they works(why they are compiled-able)?
How it works
For new R()
, it's very easy to understand what happened and I'll leave without explanation.
For Runnable::new
which stands for () -> new R()
, we need to know that Runnable
is what we called the FunctionalInterface
, and a functional interface is a interface with only one method, when we pass lambda to a method that accepts a functional interface as parameter, the lambda must matches the signature of that interface, and the action in lambda is filled to the body of that method.
The Runnable
in JDK11
looks like this:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
while the lambda () -> new R()
is compatible with the method signature - accept nothing and return nothing, so the code works, and in this case, the runTime object of the passed-in parameter looks like this:
Runnable instance with run method {
public void run() {
new R();
};
}
now we get to know why in this situation, only construction of R
triggered.
What's more
We can achieve what run(new R())
does with lambda like this:
new ConstructorRefVsNew().run(() -> System.out.println("R.run runs"));
I finally realize the question comes very tricky that the given lambda Runnable::new
is actually compatible with Runnable
interface. You can define a customize functional interface called Foo
or whatever to do the same thing
@FunctionalInterface
public interface Foo{
public abstract void run();
}
public class ConstructorRefVsNew {
public static void main(String[] args) {
new ConstructorRefVsNew().run(R::new);
}
void run(Foo f) {
f.run();
}
}
and in this case, the R::new
still works well while the new R()
cannot be passed, which indicates that the question is not a big deal but a fascinating coincidence.
Runnable runnable = R::new;
runnable instanceof R
-> false – Jalbertnew
is usually an indicator that you want to allocate some memory that you promise you will clean up yourself.R::new
just sounds like a factory method, a static function in R that creates and returns an instance of Runnable. If this instance is not captured by assigning it to a variable it might be cleaned up the moment it goes out of scope. – Simms