最近我一直在摆弄新的java8功能,以便更好地了解它们。
在使用Stream.filter
尝试某些内容时,我遇到了Predicate.java
的来源,其中我找到了isEqual
方法的以下实现:
/**
* Returns a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
令我惊讶的是这一行:: object -> targetRef.equals(object);
。
也许我正在大力推翻这一点,但我无法立即思考为什么这条线不是: targetRef::equals;
这样:
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: targetRef::equals;
}
在我看来,不必要地创建了一个lambda。
除非我遗漏了某些东西,否则我会做同样的事情。 (他们是一样的吗?)有没有理由选择当前的实施?或者这只是一个非常小的东西,它只是被忽视或没有人真正关心。
猜猜实际上会产生一个红利问题:使用一种方式比另一种方式有什么好处吗?像某种(可能非常小)的表现奖金?
答案 0 :(得分:9)
为什么这样做?
纯粹的推测,但是,也许在编写时,开发人员对 - &gt;更为舒适。并且可能::当时甚至没有工作。这些库是在修复编译器中的错误时编写的。
没有办法知道,甚至写作者也可能不记得。
无论使用方法引用还是闭包语法,在大多数情况下都会创建相同数量的对象(如本示例所示)
猜猜实际上会产生一个红利问题:使用一种方式比另一种方式有什么好处吗?像某种(可能非常小)的表现奖金?
使用方法引用意味着少一个方法调用。这可能会对内联产生间接影响,因为默认情况下级别数限制为9。例如
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
Consumer<String> lambda = s-> printStackTrace(s);
lambda.accept("Defined as a lambda");
Consumer<String> methodRef = Main::printStackTrace;
methodRef.accept("Defined as a method reference");
}
static void printStackTrace(String description) {
new Throwable(description).printStackTrace();
}
}
打印
java.lang.Throwable: Defined as a lambda
at Main.printStackTrace(Main.java:15)
at Main.lambda$main$0(Main.java:6)
at Main.main(Main.java:7)
java.lang.Throwable: Defined as a method reference
at Main.printStackTrace(Main.java:15)
at Main.main(Main.java:10)
在第一种情况下,编译器生成了一个名为Main.lambda$main$0
的方法,其中包含实际调用printStackTrace
的代码
使用其中一个或另一个产生更大差异的地方在于您可以捕获(保存值)或不捕获lambda。非捕获lambda只创建一次。
e.g。
Consumer<String> print1 = System.out::println; // creates an object each time
Consumer<String> print2 = s->System.out.println(s); // creates an object once.
在第一种情况下,如果您致电System.setOut
,它将忽略此更改,因为它拥有自己要写入的PrintStream副本。