方法参考缓存在Java 8中是个好主意吗?

方法参考缓存在Java 8中是个好主意吗?

考虑我有以下代码:

class Foo {

   Y func(X x) {...} 

   void doSomethingWithAFunc(Function<X,Y> f){...}

   void hotFunction(){
        doSomethingWithAFunc(this::func);
   }}

假设hotFunction经常被调用。那么缓存是否可取this::func,也许是这样的:

class Foo {
     Function<X,Y> f = this::func;
     ...
     void hotFunction(){
        doSomethingWithAFunc(f);
     }}

就我对java方法引用的理解而言,虚拟机在使用方法引用时会创建匿名类的对象。因此,缓存引用将仅创建该对象一次,而第一种方法在每个函数调用上创建它。它是否正确?

是否应缓存出现在代码中热位置的方法引用,或者VM是否能够对此进行优化并使缓存变得多余?是否存在关于此的一般最佳实践,或者这种高度VM实现是否特定于此类缓存是否有用?


凤凰求蛊
浏览 736回答 3
3回答

一只甜甜圈

遗憾的是,如果lambda作为一个你想要在将来某个时候删除的监听器传递,那么它是一个很好的理想的一种情况。将需要缓存的引用作为传递另一个:: method引用将不会被视为删除中的同一对象,并且原始文件将不会被删除。例如:public&nbsp;class&nbsp;Example{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;main(&nbsp;String[]&nbsp;args&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;SingleChangeListenerFail().listenForASingleChange(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SingleChangeListenerFail.observableValue.set(&nbsp;"Here&nbsp;be&nbsp;a&nbsp;change."&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SingleChangeListenerFail.observableValue.set(&nbsp;"Here&nbsp;be&nbsp;another&nbsp;change&nbsp;that&nbsp;you&nbsp;probably&nbsp;don't&nbsp;want."&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;SingleChangeListenerCorrect().listenForASingleChange(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SingleChangeListenerCorrect.observableValue.set(&nbsp;"Here&nbsp;be&nbsp;a&nbsp;change."&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SingleChangeListenerCorrect.observableValue.set(&nbsp;"Here&nbsp;be&nbsp;another&nbsp;change&nbsp;but&nbsp;you'll&nbsp;never&nbsp;know."&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;SingleChangeListenerFail &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;SimpleStringProperty&nbsp;observableValue&nbsp;=&nbsp;new&nbsp;SimpleStringProperty(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;listenForASingleChange() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observableValue.addListener(this::changed); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private<T>&nbsp;void&nbsp;changed(&nbsp;ObservableValue<?&nbsp;extends&nbsp;T>&nbsp;observable,&nbsp;T&nbsp;oldValue,&nbsp;T&nbsp;newValue&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&nbsp;"New&nbsp;Value:&nbsp;"&nbsp;+&nbsp;newValue&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observableValue.removeListener(this::changed); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;SingleChangeListenerCorrect &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;SimpleStringProperty&nbsp;observableValue&nbsp;=&nbsp;new&nbsp;SimpleStringProperty(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ChangeListener<String>&nbsp;lambdaRef&nbsp;=&nbsp;this::changed; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;listenForASingleChange() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observableValue.addListener(lambdaRef); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private<T>&nbsp;void&nbsp;changed(&nbsp;ObservableValue<?&nbsp;extends&nbsp;T>&nbsp;observable,&nbsp;T&nbsp;oldValue,&nbsp;T&nbsp;newValue&nbsp;) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&nbsp;"New&nbsp;Value:&nbsp;"&nbsp;+&nbsp;newValue&nbsp;); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observableValue.removeListener(lambdaRef); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}}在这种情况下本来不需要lambdaRef会很好。

繁花不似锦

据我所知,语言规范允许这种优化,即使它改变了可观察的行为。请参阅JSL8§15.13.3部分中的以下引用:§15.13.3方法参考的运行时评估在运行时,方法引用表达式的求值类似于类实例创建表达式的求值,只要正常完成产生对对象的引用即可。[..][..]&nbsp;要么与下面的性质的类的新实例被分配和初始化,或现有的实例与下面的属性的类的被引用。一个简单的测试表明,静态方法(can)的方法引用为每个评估产生相同的引用。以下程序打印三行,其中前两行相同:public&nbsp;class&nbsp;Demo&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String...&nbsp;args)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foobar(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foobar(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((Runnable)&nbsp;Demo::foobar); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;foobar()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((Runnable)&nbsp;Demo::foobar); &nbsp;&nbsp;&nbsp;&nbsp;}}我不能为非静态函数重现相同的效果。但是,我没有在语言规范中找到任何禁止此优化的内容。因此,只要没有性能分析来确定这种手动优化的价值,我强烈建议不要这样做。缓存会影响代码的可读性,并且不清楚它是否具有任何价值。过早优化是万恶之源。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java