Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method reference for static and instance methods

I am unable to grasp the concept of Method references in case of instance methods in Java

For example in the example below, the compiler is giving error in the list line.

I have seen the examples of String::toUpperCase.

I am confused over the point that (1) String is a class and toUpperCase is instance method. Java allows String::toUpperCase (2) Why it is not allowing in my case:- AppTest::makeUppercase

package mja;

import java.util.function.Function;
public class AppTest {

    public String makeUppercase(String source){
        return source.toUpperCase();
    }
    
    public void printFormattedString(String string, Function<String, String> formatter){
        System.out.println(formatter.apply(string));
    }
    
    public static void main(String[] args) {
        AppTest appTest = new AppTest();
        String source = "Hello World!";
        
        // Below statement compiled successfully
        appTest.printFormattedString(source, appTest::makeUppercase);

        // Getting error that non-static method can't be referenced from static context
        appTest.printFormattedString(source, AppTest::makeUppercase);
    }
}
like image 947
Niteesh Bhargava Avatar asked Apr 03 '21 11:04

Niteesh Bhargava


People also ask

How do you reference a static method?

References to static methods A static method reference refers to a static method in a specific class. Its syntax is className::staticMethodName , where className identifies the class and staticMethodName identifies the static method. An example is Integer::bitCount .

Can you refer static method through class reference?

Static methods are the methods in Java that can be called without creating an object of class. They are referenced by the class name itself or reference to the Object of that class.

What is the method reference?

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.

Which is example of method reference?

sort(stringArray, String::compareToIgnoreCase); The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b) , where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.


1 Answers

Why it is not allowing AppTest::makeUppercase?

The short answer is that AppTest::makeUppercase isn't valid "reference to an instance method of an arbitrary object of a particular type". AppTest::makeUppercase must implement interface Function<AppTest, String> to be valid reference.

Details:

There are 4 kinds of method references in Java:

  1. ContainingClass::staticMethodName - reference to a static method
  2. containingObject::instanceMethodName - reference to an instance method of a particular object
  3. ContainingType::methodName - reference to an instance method of an arbitrary object of a particular type
  4. ClassName::new - reference to a constructor

Every single kind of method reference requires corresponding Function interface implementation. You use as a parameter the reference to an instance method of an arbitrary object of a particular type. This kind of method reference has no explicit parameter variable in a method reference and requires implementation of the interface Function<ContainingType, String>. In other words, the type of the left operand has to be AppTest to make AppTest::makeUppercase compilable. String::toUpperCase works properly because the type of parameter and type of the instance are the same - String.

import static java.lang.System.out;

import java.util.Arrays;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

class ReferenceSource {

    private String value;

    public ReferenceSource() {
    }

    public ReferenceSource(String value) {
        this.value = value;
    }

    public String doInstanceMethodOfParticularObject(final String value) {
        return ReferenceSource.toUpperCase(value);
    }

    public static String doStaticMethod(final String value) {
        return ReferenceSource.toUpperCase(value);
    }

    public String doInstanceMethodOfArbitraryObjectOfParticularType() {
        return ReferenceSource.toUpperCase(this.value);
    }

    private static String toUpperCase(final String value) {
        return Optional.ofNullable(value).map(String::toUpperCase).orElse("");
    }
}

public class Main {
    public static void main(String... args) {
        // #1 Ref. to a constructor
        final Supplier<ReferenceSource> refConstructor = ReferenceSource::new;
        final Function<String, ReferenceSource> refParameterizedConstructor = value -> new ReferenceSource(value);

        final ReferenceSource methodReferenceInstance = refConstructor.get();

        // #2 Ref. to an instance method of a particular object
        final UnaryOperator<String> refInstanceMethodOfParticularObject = methodReferenceInstance::doInstanceMethodOfParticularObject;

        // #3 Ref. to a static method
        final UnaryOperator<String> refStaticMethod = ReferenceSource::doStaticMethod;

        // #4 Ref. to an instance method of an arbitrary object of a particular type
        final Function<ReferenceSource, String> refInstanceMethodOfArbitraryObjectOfParticularType = ReferenceSource::doInstanceMethodOfArbitraryObjectOfParticularType;

        Arrays.stream(new String[] { "a", "b", "c" }).map(refInstanceMethodOfParticularObject).forEach(out::print);
        Arrays.stream(new String[] { "d", "e", "f" }).map(refStaticMethod).forEach(out::print);
        Arrays.stream(new String[] { "g", "h", "i" }).map(refParameterizedConstructor).map(refInstanceMethodOfArbitraryObjectOfParticularType)
                .forEach(out::print);
    }
}

Additionally, you could take a look at this and that thread.

like image 123
Oleks Avatar answered Oct 26 '22 22:10

Oleks