我是Java中Lambda表达式的新手,所以如果这个问题显得很愚蠢,请不要太苛刻:如果我将它分配给{{1},实际的对象是什么? }?即,如果我FunctionalInterface
,我实现了一个List<String> lst = new ArrayList<>()
对象。如果我ArrayList
,会创建什么对象?并且该对象是不可变的,即有Function<String,String> fct = s -> s
?
答案 0 :(得分:2)
当你写一个lambda表达式 -
Function<String,String> fct = s -> s;
它只是创建一个实现Function<String, String>
接口的匿名类,并使用apply()
提供的实现覆盖其唯一的方法s -> s
。并将此对象分配给Function<String, String>
引用。
Function<String,String> fct = new Function<>() {
@Override
public String apply(String s) {
return s;
}
};
它是一个不可变对象,有一个public static final Function<String,String> REUSE_OFTEN = s -> String.valueOf(s)
是有意义的,因为你可以重用相同的对象来应用不同输入的这个操作。
答案 1 :(得分:1)
即,如果我做List lst = new ArrayList&lt;&gt;()我实现了 ArrayList对象。
您实例化了ArrayList
。
如果我执行Function,会创建什么对象 fct = s - &gt; S'并且该对象是不可变的,即它是否有意义 有一个公共静态最终函数REUSE_OFTEN = s - &gt; 将String.valueOf(S)?
在字节代码方面,Lambda与匿名类不同,在行为/功能方面也是如此。最后一个足够接近但不完全相同。
以下是两个执行相同操作的方法,一个使用lambda,另一个使用匿名类:
public class CompareBoth {
public void lambda() {
Function<String,String> fct = s -> s;
fct.apply("a");
}
public void anonymousClass() {
Function<String,String> fct = new Function<String, String>() {
@Override
public String apply(String t) {
return t;
}
};
fct.apply("a");
}
}
这里是反汇编的代码:
public class cli.CompareBoth {
public cli.CompareBoth();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void lambda();
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
5: astore_1
6: aload_1
7: ldc #3 // String a
9: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
14: pop
15: return
public void anonymousClass();
Code:
0: new #5 // class cli/CompareBoth$1
3: dup
4: aload_0
5: invokespecial #6 // Method cli/CompareBoth$1."<init>":(Lcli/CompareBoth;)V
8: astore_1
9: aload_1
10: ldc #3 // String a
12: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
17: pop
18: return
}
我们可以看到JVM对它们的区别对待。
实施的实际对象是什么?
创建lambda时,将执行此JVM指令:
Java 7中引入的0:invokedynamic#2,0 // InvokeDynamic #0:申请:()Ljava / util的/功能/功能;
InvokeDynamic
被指定为字节码指令,通过动态方法调用来促进动态语言(用于JVM)的实现。
您可以阅读this javaworld page以获取更多信息。
现在,随着你的发展真的重要吗?
在大多数情况下,它没有
功能接口的功能非常接近匿名接口,但存在多种细微差别
从概念上讲,我认为以这种方式考虑它们是可以接受的。
关于功能界面不变性:
功能接口可能具有状态,但设计为不可变的。
所以如果有意义,你可以重复使用它们
但{J}可以优化InvokeDynamic
因此,您不应该在代码中重复使用它们,只是为了节省一些对象
而不是在常量或变量中提取函数接口,因为它使事情更清晰或避免重复。