Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 method reference: how to determine which method to take?

Tags:

java

java-8

Lets say we have the following class:

public class NameCreator {

    public String createName(String lastname) {
        return lastname;
    }

    public String createName(String lastname, String firstName) {
        return lastname + " " + firstname
    }

    ...
}

If I want to call it via Java 8 method reference:

NameCreator::createName

I will get the error:

Cannot resolve method createName

How can I define which of those methods I want to be called?

like image 605
Mulgard Avatar asked Jul 13 '18 10:07

Mulgard


People also ask

How does method reference work in Java 8?

The method references can only be used to replace a single method of the lambda expression. A code is more clear and short if one uses a lambda expression rather than using an anonymous class and one can use method reference rather than using a single function lambda expression to achieve the same.

Does method references point to methods using their names?

In those cases, it's often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

Which of the following is correct about Java 8 method references?

Q 7 - Which of the following is correct about Java 8 method references? A - Method references help to point to methods by their names.


2 Answers

NameCreator::createName implies that either the method is static (kind #1 in the table below), or that the functional interface target also takes an instance of the class (kind #3, for example
BiFunction<NameCreator, String, String>). Your methods are not static, and so presumably your target does not take an instance, which is why you get the "Cannot resolve method" error. You probably want to use the method reference on an instance (kind #2). From within the class, you can use:

Function<String, String> func = this::createName

From outside the class you can use:

NameCreator creator = new NameCreator();
Function<String, String> func = creator::createName;

As to whether the one- or two-parameter version is used, it depends on what functional interface is being targeted. The above will use your first method, because Function<String, String> takes a String and returns a String. The following functional interface, as an example, would use your second method:

NameCreator creator = new NameCreator();
BiFunction<String, String, String> func = creator::createName;

See: Function, BiFunction, and the whole java.util.function package

You may also be interested in the Java tutorial on method references, specifically this part:


There are four kinds of method references:

Kind                                                   | Example
==============================================================================================
Reference to a static method                           | ContainingClass::staticMethodName
-------------------------------------------------------+--------------------------------------
Reference to an instance method of a particular object | containingObject::instanceMethodName
-------------------------------------------------------+--------------------------------------
Reference to an instance method of an arbitrary object | ContainingType::methodName
of a particular type                                   |
-------------------------------------------------------+--------------------------------------
Reference to a constructor                             | ClassName::new
==============================================================================================
like image 155
Michael Avatar answered Sep 28 '22 14:09

Michael


Method references rely on inference. So without proper context from which the compiler can infer the target functional interface, that resolution error is raised.

You should assign it to an interface type that declares a method matching the signature (or use it in a context where the target type is defined, such as a method argument).

For example:

interface INameCreator {
    String create(String name);
}

interface INamesCreator {
    String create(String firstName, String lastName);
}

And then you can use the method references:

//match NameCreator.createName(String)
INameCreator creator = this::createName //within the class
INameCreator creator = nameCreatorInstance::createName 

And

//match NameCreator.createName(String, String)
INamesCreator creator = this::createName //within the class
INamesCreator creator = nameCreatorInstance::createName

If the method were static, you would be able to use the NameCreator::createName syntax in the same context.

like image 23
ernest_k Avatar answered Sep 28 '22 15:09

ernest_k