lonecloud
lonecloud

Reputation: 413

Java lambda method and new Object

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?

Upvotes: 23

Views: 6371

Answers (4)

Oleksandr Pyrohov
Oleksandr Pyrohov

Reputation: 16246

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();

Upvotes: 11

TomVW
TomVW

Reputation: 1580

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.

Upvotes: 42

luk2302
luk2302

Reputation: 57154

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.

Upvotes: 20

Eran
Eran

Reputation: 393936

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();

Upvotes: 6

Related Questions