为什么 Function.identity() 返回 lambda 表达式而不是保存恒等 lambda 的强制转换静态字段?

问题描述 投票:0回答:1

正如我使用源代码的 JDK 版本中所见,

Function.identity()
的定义如下:

static <T> Function<T, T> identity() {
    return t -> t;
}

对我来说,旧的 Java 7 和旧版本背景及其内部类可以捕获太多内容,看起来每次调用

identity
函数时,Function.identity() 函数中的 lambda 都是
实例化
。我想知道如果函数返回强制转换字段有什么区别?

例如,我有两个类以上述两种方式定义 lambda。

final class DynamicLambda {

    private DynamicLambda() {
        throw new AssertionError();
    }

    static Function<Object, Object> identity() {
        return o -> o;
    }

}
final class StaticLambda {

    private StaticLambda() {
        throw new AssertionError();
    }

    static final Function<Object, Object> identity = o -> o;

}

使用

javap
-p
选项时,它们的
-c
类会像这样被反汇编:

Compiled from "DynamicLambda.java"
final class DynamicLambda {
  private DynamicLambda();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: new           #7                  // class java/lang/AssertionError
       7: dup
       8: invokespecial #9                  // Method java/lang/AssertionError."<init>":()V
      11: athrow

  static java.util.function.Function<java.lang.Object, java.lang.Object> identity();
    Code:
       0: invokedynamic #10,  0             // InvokeDynamic #0:apply:()Ljava/util/function/Function;
       5: areturn

  private static java.lang.Object lambda$identity$0(java.lang.Object);
    Code:
       0: aload_0
       1: areturn
}
Compiled from "StaticLambda.java"
final class StaticLambda {
  static final java.util.function.Function<java.lang.Object, java.lang.Object> identity;

  private StaticLambda();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: new           #7                  // class java/lang/AssertionError
       7: dup
       8: invokespecial #9                  // Method java/lang/AssertionError."<init>":()V
      11: athrow

  private static java.lang.Object lambda$static$0(java.lang.Object);
    Code:
       0: aload_0
       1: areturn

  static {};
    Code:
       0: invokedynamic #10,  0             // InvokeDynamic #0:apply:()Ljava/util/function/Function;
       5: putstatic     #14                 // Field identity:Ljava/util/function/Function;
       8: return
}

唯一的字节码差异我看到是,

invokedynamic
被调用的次数与调用
DynamicLambda.identity()
的次数相同,或者在其静态初始化程序中为
StaticLambda.identity
调用一次。

从语义角度来看,“动态”方法的优点是 lambda 表达式类型推断,因为“静态”方法需要未经检查的类型转换。从调用站点的角度来看,唯一的区别是用于获取恒等函数的指令:

invokestatic
用于“动态”方法,
getstatic
用于“静态”方法。

这两者之间的真正区别是什么?

Function.identity()
是这样实现的吗?它们如何影响内存占用以及可能的性能?

java lambda java-8
1个回答
0
投票

Function.identity()
每次都返回相同的实例。

所以唯一的区别是它会根据调用者所需的类型进行调整。这给了我们想要的类型安全,

© www.soinside.com 2019 - 2024. All rights reserved.