Jef*_*oom 14 java lambda java-8 method-reference
考虑以下课程:
import java.util.Objects;
import java.util.function.Predicate;
public class LambdaVsMethodRef {
public static void main(String[] args) {
Predicate<Object> a = Objects::nonNull;
Predicate<Object> b = x -> x != null;
}
}
Run Code Online (Sandbox Code Playgroud)
第一个谓词是从方法引用创建的,另一个是lambda表达式.这些谓词具有相同的行为(nonNull正文是正确的return obj != null;).lambda缩短了两个字符(可能允许流管道适合一行).
除了代码风格,和之间有什么区别?换句话说,我应该更喜欢一个吗?Objects::nonNullx -> x != null
拉姆达-dev的和λ-库-规格- {观察员,专家}邮件列表邮件提isNull,nonNull以及isNotNull(初名)并没有解决这个问题.(我很惊讶没有人质疑添加Objects方法,因为它们可以用lambda轻松替换,但另一方面,也是如此Integer::sum.)
我也查看了字节码javap.唯一的区别是传递给lambda metafactory bootstrap方法的方法句柄:
BootstrapMethods:
0: #16 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#17 (Ljava/lang/Object;)Z
#18 invokestatic java/util/Objects.nonNull:(Ljava/lang/Object;)Z
#17 (Ljava/lang/Object;)Z
1: #16 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#17 (Ljava/lang/Object;)Z
#20 invokestatic LambdaVsMethodRef.lambda$main$1:(Ljava/lang/Object;)Z
#17 (Ljava/lang/Object;)Z
Run Code Online (Sandbox Code Playgroud)
当然,对于方法引用和lambdas来说,元数据可以在JVM的奇思妙想中做不同的事情,所以这并不是很有效.
Stu*_*rks 32
如您所述,lambda的语义x -> x != null和方法引用Objects::nonNull实际上是相同的.我很难想到任何实际可观察到的差异,缺少使用反射挖掘课程,或类似的东西.
使用lambda上的方法引用有一个小的空间优势.使用lambda,lambda的代码被编译成包含类的私有静态方法,然后通过引用此静态方法调用lambda metafactory.在方法引用的情况下,该方法已经存在于java.util.Objects类中,因此lambda metafactory是通过引用现有方法来调用的.这样可以节省适度的空间.
考虑这些小班:
class LM { // lambda
static Predicate<Object> a = x -> x != null;
}
class MR { // method reference
static Predicate<Object> a = Objects::nonNull;
}
Run Code Online (Sandbox Code Playgroud)
(感兴趣的读者应该javap -private -cp classes -c -v <class>查看这些编译方式之间的详细差异.)
这导致lambda case为1,094字节,方法参考case为989字节.(Javac 1.8.0_11.)这不是一个巨大的区别,但如果您的程序可能有大量像这样的lambdas,您可能会考虑使用方法引用节省空间.
此外,方法引用更有可能是jit编译和内联而不是lambda,因为方法引用可能使用得更多.这可能会导致性能微小改善.但是,这似乎不太可能产生实际差异.
虽然你特别说"除了代码风格......",但这主要是关于风格.这些小方法专门添加到API中,以便程序员可以使用名称而不是内联lambda.这通常会提高代码的可理解性.另一点是方法引用通常具有显式类型信息,可以帮助解决困难类型的推理案例,例如嵌套的Comparators.(但这并不适用于Objects::nonNull.)添加强制转换或显式类型的lambda参数会增加很多混乱,因此在这些情况下,方法引用是明显的胜利.
| 归档时间: |
|
| 查看次数: |
8749 次 |
| 最近记录: |