静态方法和实例方法的方法参考

Nit*_*ava 5 java method-reference

在 Java 中的实例方法的情况下,我无法掌握方法引用的概念

例如,在下面的示例中,编译器在列表行中给出错误。

我看过 String::toUpperCase 的例子。

我对 (1) String 是一个类而 toUpperCase 是实例方法这一点感到困惑。Java 允许 String::toUpperCase (2) 为什么在我的情况下不允许:- 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ole*_*ndr 6

为什么不允许AppTest::makeUppercase

简而言之,“对特定类型的任意对象的实例方法的引用”AppTest::makeUppercase无效。 必须实现接口AppTest::makeUppercaseFunction<AppTest, String>才能成为有效引用。

细节:

Java中有4种方法引用:

  1. ContainingClass::staticMethodName- 静态方法的引用
  2. containingObject::instanceMethodName- 对特定对象的实例方法的引用
  3. ContainingType::methodName- 对特定类型的任意对象的实例方法的引用
  4. ClassName::new- 对构造函数的引用

每一种方法引用都需要相应的Function接口实现。您可以使用对特定类型的任意对象的实例方法的引用作为参数。这种方法引用在方法引用中没有显式参数变量,并且需要接口的实现Function<ContainingType, String>。换句话说,左操作数的类型必须是AppTestAppTest::makeUppercase编译的。String::toUpperCase工作正常,因为参数类型和实例类型相同 - 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,您可以看看这个那个线程。