gpt4 book ai didi

Java 8 Streams map API - 方法引用解读

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:04:29 25 4
gpt4 key购买 nike

示例代码:

class Outer {
public Integer i;

Outer(Integer i) {
this.i = i;
}

public int getVal() { return i; }
}

class MyClass {

public Integer f(Outer o) { return o.getVal();};

public void main() {

MyClass g = new MyClass();

List<Integer> l1 = Arrays.asList(new Outer(2)).stream().map(g::f).collect(Collectors.toList());
List<Integer> l2 = Arrays.asList(new Outer(2)).stream().map(Outer::getVal).collect(Collectors.toList());
}
}

使用任一方法引用

  1. Outer::instanceMethod没有参数,基本上是一个 Supplier<T>功能界面。 [1]

  2. MyClass::instanceMethod接受类型为 Outer 的参数并且是 Function<T,R>功能界面。 [1]

有效。那么map怎么办?函数知道将选项 (1) 中的函数应用于流的对象,但将流对象传递给选项 (2) 中的函数?

[1] https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

最佳答案

首先,map 方法本身并不知道如何处理方法引用。那是编译器的工作。在这两种情况下,map 都期望:

Function<? super PackageName.outer,? extends Integer>

根据 docs,对于您的特定问题,这两种方法都引用了是对特定对象的实例方法的引用

关于编译器如何处理 lambda 和方法引用并将它们转换为字节码 this document强烈推荐阅读。与您的问题最相关的部分(强调我的总结):

When the compiler encounters a lambda expression, it first lowers (desugars) the lambda body into a method whose argument list and return type match that of the lambda expression, possibly with some additional arguments (for values captured from the lexical scope, if any.) At the point at which the lambda expression would be captured, it generates an invokedynamic call site, which, when invoked, returns an instance of the functional interface to which the lambda is being converted. This call site is called the lambda factory for a given lambda. The dynamic arguments to the lambda factory are the values captured from the lexical scope. The bootstrap method of the lambda factory is a standardized method in the Java language runtime library, called the lambda metafactory. The static bootstrap arguments capture information known about the lambda at compile time (the functional interface to which it will be converted, a method handle for the desugared lambda body, information about whether the SAM type is serializable, etc.)

Method references are treated the same way as lambda expressions, except that most method references do not need to be desugared into a new method; we can simply load a constant method handle for the referenced method and pass that to the metafactory

Instance-capturing method reference forms include bound instance method references (s::length, captured with reference kind invokeVirtual)

你的 2 个案例的字节码是:

  1. outer::instanceMethod

    // handle kind 0x5 : INVOKEVIRTUAL
    PackageName/outer.getVal()I,
    (LPackageName/outer;)Ljava/lang/Integer;
  2. MyClass::instanceMethod

    // handle kind 0x5 : INVOKEVIRTUAL
    PackageName/MyClass.f(LPackageName/outer;)Ljava/lang/Integer;,
    (LPackageName/outer;)Ljava/lang/Integer;

请注意,虽然第二行在第二种情况下更复杂,但最后一行是相同的。在这两种情况下,编译器只看到一个接受 outer 并返回 Integer 的函数。这符合 map 的预期。

方法引用在语言规范中描述 15.13 Method Reference Expressions . 15.13.3 Run-Time Evaluation of Method References 中提到了方法引用的目标引用是方法的隐式第一个参数这一事实。 .

If the compile-time declaration is an instance method, then the target reference is the first formal parameter of the invocation method. Otherwise, there is no target reference

关于Java 8 Streams map API - 方法引用解读,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41532611/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com