方法参考缓存在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实现是否特定于此类缓存是否有用?
3 回答
一只甜甜圈
TA贡献1836条经验 获得超5个赞
遗憾的是,如果lambda作为一个你想要在将来某个时候删除的监听器传递,那么它是一个很好的理想的一种情况。将需要缓存的引用作为传递另一个:: method引用将不会被视为删除中的同一对象,并且原始文件将不会被删除。例如:
public class Example{ public void main( String[] args ) { new SingleChangeListenerFail().listenForASingleChange(); SingleChangeListenerFail.observableValue.set( "Here be a change." ); SingleChangeListenerFail.observableValue.set( "Here be another change that you probably don't want." ); new SingleChangeListenerCorrect().listenForASingleChange(); SingleChangeListenerCorrect.observableValue.set( "Here be a change." ); SingleChangeListenerCorrect.observableValue.set( "Here be another change but you'll never know." ); } static class SingleChangeListenerFail { static SimpleStringProperty observableValue = new SimpleStringProperty(); public void listenForASingleChange() { observableValue.addListener(this::changed); } private<T> void changed( ObservableValue<? extends T> observable, T oldValue, T newValue ) { System.out.println( "New Value: " + newValue ); observableValue.removeListener(this::changed); } } static class SingleChangeListenerCorrect { static SimpleStringProperty observableValue = new SimpleStringProperty(); ChangeListener<String> lambdaRef = this::changed; public void listenForASingleChange() { observableValue.addListener(lambdaRef); } private<T> void changed( ObservableValue<? extends T> observable, T oldValue, T newValue ) { System.out.println( "New Value: " + newValue ); observableValue.removeListener(lambdaRef); } }}
在这种情况下本来不需要lambdaRef会很好。
繁花不似锦
TA贡献1851条经验 获得超4个赞
据我所知,语言规范允许这种优化,即使它改变了可观察的行为。请参阅JSL8§15.13.3部分中的以下引用:
§15.13.3方法参考的运行时评估
在运行时,方法引用表达式的求值类似于类实例创建表达式的求值,只要正常完成产生对对象的引用即可。[..]
[..] 要么与下面的性质的类的新实例被分配和初始化,或现有的实例与下面的属性的类的被引用。
一个简单的测试表明,静态方法(can)的方法引用为每个评估产生相同的引用。以下程序打印三行,其中前两行相同:
public class Demo { public static void main(String... args) { foobar(); foobar(); System.out.println((Runnable) Demo::foobar); } public static void foobar() { System.out.println((Runnable) Demo::foobar); }}
我不能为非静态函数重现相同的效果。但是,我没有在语言规范中找到任何禁止此优化的内容。
因此,只要没有性能分析来确定这种手动优化的价值,我强烈建议不要这样做。缓存会影响代码的可读性,并且不清楚它是否具有任何价值。过早优化是万恶之源。
添加回答
举报
0/150
提交
取消