Dav*_*lfe 8 java lambda constructor java-8
当我使用在构造函数中调用可覆盖方法的lambda添加事件侦听器时,我收到警告.如果我使用方法引用,我不会收到有关可覆盖方法或泄漏此方法的任何警告.我应该避免构造函数中的方法引用还是安全的?
这是一个简单的例子:
public class SomeClass {
public SomeClass(SomeObj obj) {
obj.addListener(this::handleEvent); // no warnings, is it really safe?
obj.addListener((event) -> handleEvent(event)); // warning about overridable method in constructor
}
private void handleEvent(Event event) {
event.doSomething(someMethod());
}
private void someMethod() {
...
}
}
Run Code Online (Sandbox Code Playgroud)
不,这绝对不是安全的.您正在发布this在完全构造对象之前可能被外来代码访问的位置.无论是通过匿名类还是通过lambda或方法引用,都可以从构造函数注册侦听器.你的例子相当于我在本文(12年前)警告过的成语:https://www.ibm.com/developerworks/library/j-jtp0618/
这里方法参考的参与是一个红鲱鱼; 问题是,您正在将对部分构造的对象的引用提供给您无法控制的代码.
编译器无法警告你所有事情; 只是因为没有警告并不意味着你的代码是正确的:)
方法引用和lambdas都评估相同的东西,一个功能接口:
所以,这两者基本上是等价的.在方法引用的情况下,目标是显式的this,并且在lambda的情况下,它是隐式的this.所以,他们的"警告"是一样的.接下来的问题是:哪一个编译器出错了?警告是错误的还是没有警告?
警告的原因是this构造函数泄漏有几个很大的危险.一个涉及多线程:final如果this从引用泄漏,任何内存可见性保证您从字段语义(以及一些其他保证)获得的内容都消失了.另一个问题是该addListener方法将this在构造函数完成之前立即调用该方法.也就是说,它将在部分构造的对象上调用方法.这对于可覆盖的方法尤其有问题,因为它可能是这个构造函数用于其他人的超类,并且其他人已经覆盖了所讨论的方法.在这种情况下,您将在该子类上调用该方法,其构造函数甚至还没有机会启动(因为首先运行超类的构造函数).
所以,是的,lambda上的警告是正确的.它也应该用于方法参考.