23

I have the following code:

public class RefDemo {

    static class Demo implements Runnable {

        public Demo() {
            System.out.println(this.toString() + "-----");
        }

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

    public static void main(String[] args) {
        Runnable runnable = Demo::new; // lambda ref constructor method
        runnable.run(); // does not do anything
        System.out.println(runnable);
        Runnable demo = new Demo(); // using new to create a Demo instance
        demo.run();
        System.out.println(demo);
    }
}

Which prints:

RefDemo$Demo@7291c18f----- // lambda run constructor method print
RefDemo$$Lambda$1/793589513@34a245ab // main method print
RefDemo$Demo@7cc355be-----
run
RefDemo$Demo@7cc355be

I don't know why the code does not print run when calling runnable.run();

Why does that happen?

4
  • 10
    runnable.run() calls the constructor, not the run method of Demo. Commented Apr 30, 2018 at 9:07
  • 7
    new Demo() and Demo::new are not equivalent. Commented Apr 30, 2018 at 17:38
  • 3
    try runnable.run().run() Commented May 1, 2018 at 23:10
  • 1
    the answer's da-do-run().run() Commented May 4, 2018 at 7:28

4 Answers 4

42

This code

Runnable runnable = Demo::new;

Is equivalent to this code

Runnable runnable = new Runnable() {
    @Override 
    public void run() {
        new Demo();
    }
};

So you are not referring to the run method of Demo but to the constructor.

Sign up to request clarification or add additional context in comments.

Comments

20

You are simply using Runnable in too many places and confusing yourself. The following code makes it a bit clearer what is happening:

public class RefDemo {

    static class Demo {

        public Demo() {
            System.out.println(this.toString() + "-----");
        }

        public void something() {
            System.out.println("something");
        }
    }

    public static void main(String[] args) {
        Runnable runnable = Demo::new; 
        runnable.run();

        System.out.println(runnable);

        Demo demo = new Demo();
        demo.something();

        System.out.println(demo);
    }
}

Runnable runnable = Demo::new; means that you now have a reference to the constructor of Demo (which still works after dropping the conformance to the Runnable interface). And you store that reference in a variable of type Runnable which only works because their functional interfaces are compatible. Calling run on that reference then simply calls the constructor, not the run / something method of Demo.

3 Comments

Runnable runnable = Demo::new; this mean only using lambda create a virtual anon instances which implements Runnable interface, but why it can print RefDemo$Demo@7291c18f----- //lambda run constructor methods print?
@lonecloud what if for the purpose of the example you re-write it like this Runnable x = new Runnable() { @Override public void run() { new Demo(); } }; would that make more sense?
@lonecloud because you still end up calling the constructor, and inside the constructor this / toString still refers to a Demo instance. Printing the runnable itself however outputs the anonymous name of the lambda.
11

The lines:

Runnable runnable = Demo::new;
runnable.run();

Are equivalent to:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        new Demo(); // Creates an instance of the Demo class, and nothing more
    }
};
runnable.run();

At the same time, your intention was to invoke the run method from the Demo class through a method reference. Therefore, I assume you meant the following:

Runnable runnable = new Demo()::run;
runnable.run();
// But, this is a little bit redundant...

The above code is equivalent to:

Demo demo = new Demo();
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        demo.run();
    }
};
runnable.run();

P.S. You don't really need a method reference here, so just write:

new Demo().run();

Or:

Runnable demo = new Demo();
demo.run();

Comments

6

Demo::new is the constructor of the Demo class. Since you assign it to a reference to the Runnable interface, calling runnable.run() invokes the constructor and creates a new Demo instance. The run() method is not executed.

If you want to define a Runnable instance that calls Demo's run() method using a method reference, you can write:

Runnable runnable = new Demo()::run;

Of course, since Demo already implements Runnable, it's much simpler to just write:

Runnable runnable = new Demo();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.