Java 8 - Constructor Reference - The type Select d

2020-04-21 00:57发布

I defined one FunctionalInterface as below:

@FunctionalInterface
public interface BaseAction {
   public void execute(final DataObj dataObj) throws Exception;
}

Then, a class implementing the same as follows:

public class Select implements BaseAction{

    @Override
    public void execute(final DataObj dataObj) {
        //some operations on dataObj here..
    }
}

And when I tried instantiating the class Select using syntax prior to Java 8, compiles for me, as follows:

public BaseAction getAction(final String action) {      
    switch (action) {
          case "SELECT": return new Select(); //Works
     }
        return null;
}

But, when I tried instantiating it using Java 8 syntax, IDE starts complaining me "The type Select does not define Select(DataObj) that is applicable here",

public BaseAction getAction(final String action) {
    switch (action) {
         case "SELECT": return Select::new; //Compile error here..
    }
    return null;
}

Any idea how can I fix it?

标签: java java-8
2条回答
smile是对你的礼貌
2楼-- · 2020-04-21 01:43

What you're using is not "the Java 8 syntax for creating an object". You're using a reference to the constructor, so in a way the difference between your two pieces of code is the same as between

someObject.toString()

and

someObject.toString

The first one instantiates a new object, the second one points to the thing used to instantiate the new object, but doesn't call it (the more precise analogy would be to someObject::toString, by the way).

If all you want to do is to instantiate a Select object, then just keep using the "old" code, it's exactly how you'll do it in Java 8.

The new syntax is useful if you want to pass the specific constructor to use to some piece of code that wants to be agnostic to which constructor/type is used.

You could do something like that:

public void executeBaseAction(DataObject data, Supplier<BaseAction> baseActionSupplier) {
    BaseAction action = baseActionSupplier.get();
    action.execute(data);
}

And call it like this:

executeBaseAction(data, Select::new);
查看更多
淡お忘
3楼-- · 2020-04-21 01:50

The method reference Select::new is a reference to a constructor, and it doesn't match the required functional interface signature, taking a DataObj parameter and returning void.

You'll need a Select reference to create the method reference, but it must refer to the execute method. This should work:

case "SELECT": return new Select()::execute;

As you've noted, return new Select(); works, and it's less verbose. I would still use this, but the method reference above should work.

查看更多
登录 后发表回答