Java 为什么Predicate.isEqual的实现方式是这样的?
最近我一直在摆弄新的java8特性,以便更好地理解它们 在尝试使用Java 为什么Predicate.isEqual的实现方式是这样的?,java,java-8,Java,Java 8,最近我一直在摆弄新的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
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);
}
在我看来,这是一个不必要的lambda的创造
除非我错过了什么,否则对我来说,他们也一样。(他们是相同的权利吗?)选择当前实施的原因是什么?或者这仅仅是一件非常小的事情,只是被忽视了,或者没有人真正关心
我猜这实际上导致了一个额外的问题:使用一种方法比另一种方法有什么好处吗?比如某种(可能很小的)绩效奖金
为什么要这样做
纯粹是猜测,但可能在编写时,开发人员对->和可能的::更为熟悉,当时甚至不起作用。这些库是在修复编译器中的错误时编写的
没有办法知道,甚至写这本书的人也可能不记得了
无论使用方法引用还是闭包语法,在大多数情况下都会创建相同数量的对象(如本例所示) 我猜这实际上导致了一个额外的问题:使用一种方法比另一种方法有什么好处吗?比如某种(可能很小的)绩效奖金 使用方法引用意味着少调用一个方法。这可能会对内联产生间接影响,因为默认情况下级别数限制为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();
}
}
在第一种情况下,编译器生成了一个名为Main.lambda$Main$0
的方法,其中包含实际调用printStackTrace
使用一个或另一个会产生更大差异的地方是,您可以使用捕获(保存值)或不捕获lambda。非捕获lambda只创建一次
e、 g
Consumer print1=System.out::println;//每次创建一个对象
消费者打印2=s->System.out.println(s);//创建一个对象一次。
在第一种情况下,如果调用
System.setOut
,它将忽略此更改,因为它有自己的打印流副本要写入。方法引用与显式lambda在同一台研磨机中结束。这两种方法都需要相同的实现技术。我认为没有人能够回答这个问题。。。希望是编写代码的人。。。即使这样,也不太确定。这是谓词工厂,每个流构造只调用一次。在这两种情况下,都有相同的函数接口实例,其方法正在被调用。这一切都完全一样。@OlleKelderman运行时没有真正的区别。方法引用比较干净,但在运行时,所做的工作量和创建的对象数量是相同的。@OlleKelderman有一点,但最好理解其中的差异,即使在99%的时间里,这并不重要。看到我的答案了。至于为什么会这样做的最初问题,我猜答案是“我们很可能永远都不知道,而且这可能不重要”@OlleKelderman现在想象一组lambda,在第一种情况下,如果你把它加两次,你会得到一组2,在第二种情况下,你会得到一组1。尝试删除一个,您可能会分别得到2和0的大小。@OlleKelderman可能在编写时,开发人员对->
更为熟悉,可能:
当时甚至不起作用。这些库是在修复编译器中的错误时编写的@MarkoTopolnik在lambda风格的语法中,一个静态
方法被添加到包含实际代码的类中,一个对该生成方法的方法引用被添加到字节码中。如果使用方法引用语法,则不会添加此额外的静态方法,这意味着内联的级别减少了一个。由于表达式包含Objects::isNull
,因此作者不太可能“对->更满意”,也不太可能::不起作用。可能是instance::method
表单不起作用或者作者不知道,但是似乎对::操作符有偏好,否则,它将是object->Objects.isNull(object)
…
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)
Consumer<String> print1 = System.out::println; // creates an object each time
Consumer<String> print2 = s->System.out.println(s); // creates an object once.