9

I am reading Java 8 book, and it comes with a sample I reproduce:

@FunctionalInterface
public interface Action {
    public void perform();
}

An Implementor:

public final class ActionImpl implements Action {
    public ActionImpl() {
        System.out.println("constructor[ActionIMPL]");
    }

    @Override
    public void perform() {
        System.out.println("perform method is called..");
    }    
}

A caller:

public final class MethodReferences {

    private final Action action;

    public MethodReferences(Action action) {
        this.action = action;
    }

    public void execute() {
        System.out.println("execute->called");
        action.perform();
        System.out.println("execute->exist");
    }

    public static void main(String[] args) {
        MethodReferences clazz = new MethodReferences(new ActionImpl());
        clazz.execute();
    }
}

If this is called the following is print into the output:

constructor[ActionIMPL]
execute->called
perform method is called..
execute->exist

Everything is all right but if I use method references not perform message method is printed! Why is this, am I missing something?

If I use this code:

MethodReferences clazz = new MethodReferences(() -> new ActionImpl());
clazz.execute();

Or this code:

final MethodReferences clazz = new MethodReferences(ActionImpl::new);

This is printed:

execute->called
constructor[ActionIMPL]
execute->exist

No exception message or anything else is printed. I am using Java 8 1.8.25 64bit.

Update

For readers that are studying like me, this is the right running code.

I have created a class the caller.

Because I need to implement a empty method "perform from the Action functional interface" which I need to pass as parameter to class constructor MethodReference I reference the "constructor of the MethodReferenceCall which is a empty constructor" and I can use it.

public class MethodReferenceCall {
    public MethodReferenceCall() {
        System.out.println("MethodReferenceCall class constructor called");
    }

    public static void main(String[] args) {
        MethodReferenceCall clazz = new MethodReferenceCall();
        MethodReferences constructorCaller = new MethodReferences(MethodReferenceCall::new);
        constructorCaller.execute();
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
chiperortiz
  • 4,751
  • 9
  • 45
  • 79
  • 1
    You have an non-executed action inside another action. You _could_ achieve what you want with the lambda `MethodReferences clazz = new MethodReferences(() -> new ActionImpl().perform()); clazz.execute();` – knittl Nov 21 '21 at 10:40

1 Answers1

14

This

MethodReferences clazz = new MethodReferences(() -> new ActionImpl());

does not use method reference, it uses a lambda expression. The functional interface is Action's

public void perform();

So

() -> new ActionImpl()

gets translated into something similar to

new Action() {
    public void perform() {
        new ActionImpl();
    }
}

Similarly, in

MethodReferences clazz = new MethodReferences(ActionImpl::new);

the ActionImpl::new, which does use a constructor reference, is translated into something like

new Action() {
    public void perform() {
        new ActionImpl();
    }
}

This ActionImpl::new does not invoke new ActionImpl(). It resolves to an instance of the expected type whose functional interface method is implemented as invoking that constructor.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 2
    could you explained a little more simple.. sorry – chiperortiz Oct 21 '14 at 23:27
  • 5
    @chiperortiz A method _reference_ is not a method _invocation_. Instead, it becomes the body of the target functional interface. – Sotirios Delimanolis Oct 21 '14 at 23:28
  • 7
    @chiperortiz Basically, your first (working) example creates a new `ActionImpl`, and when the `perform` method of that is called, it prints a message. The second example doesn't create a new `ActionImpl`. It creates a new object whose type is an _anonymous_ class that implements `Action`. When the `perform` method of that anonymous-class object is called, its `perform` method creates a new `ActionImpl` (and then throws it away). – ajb Oct 21 '14 at 23:49
  • Perfect explanation! What if ActionImpl implements 2 functional interfaces, How does it gets translated? – Vipin Aug 08 '17 at 05:19