javajava-8method-referenceconstructor-reference

Java 8 constructor method references


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

Solution

  • 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.