我的印象是以下lambda表达式
() -> object.method()
相当于方法参考
object::method
这与IntelliJ更加复杂,IntelliJ一直让我烦恼,用后者代替前者。
但是,我偶然发现了一个似乎并非如此的情况。我有一些代码需要访问各种bean的很多属性,这些属性可能为null,也可能不为null。因为我不想写很多
T1 var1 = bean1==null?null:bean1.getPropertyA()
T2 var2 = bean2==null?null:bean2.getPropertyB()
T3 var3 = bean3==null?null:bean3.getPropertyC()
行,我试图变得聪明,并编写了以下方法:
private <T> T nullSafeGet(final Object object, Supplier<T> call) {
return object != null ? call.get() : null;
}
我现在可以编写以下内容:
T1 var1 = nullSafeGet(bean1, () -> bean1.getPropertyA());
T2 var1 = nullSafeGet(bean2, () -> bean2.getPropertyB());
T3 var1 = nullSafeGet(bean3, () -> bean3.getPropertyC());
如果Bean为null
,则不调用getter并将变量设置为null
,这是完美的方法。
但是,我想使上面的代码块更具可读性(并且IntelliJ也建议我这样做),所以我将其更改为:
T1 var1 = nullSafeGet(bean1, bean1::getPropertyA);
T2 var1 = nullSafeGet(bean2, bean2::getPropertyB);
T3 var1 = nullSafeGet(bean3, bean3::getPropertyC);
当bean为非null时,其行为完全相同。但是,如果这些bean中的任何一个为null
,则对nullSafeGet的调用将引发NullPointerException
。
据我所知,方法引用bean::getProperty
不会被懒惰地求值(即,仅当调用nullSafeGet()中的供应商时),而lambda表达式仅在需要时才求值。
我做错什么了吗?或者这两种表示在各个方面确实不相等吗?
以下代码演示了该问题:
import org.junit.Test;
import java.util.function.Supplier;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class PersonTest {
private static final String NAME = "Fester Bettertester";
@Test
public void testAccessNonNullReference() {
Person person = new Person(NAME);
assertEquals(NAME, nullSafeGet(person, person::getName));
}
@Test
public void testAccessNonNullLambda() {
Person person = new Person(NAME);
assertEquals(NAME, nullSafeGet(person, () -> person.getName()));
}
@Test
public void testAccessNullLambda() {
Person person = null;
assertNull(nullSafeGet(person, () -> person.getName()));
}
@Test
public void testAccessNullReference() {
Person person = null;
assertNull(nullSafeGet(person, person::getName)); // this throws a null pointer exception
}
private <T> T nullSafeGet(final Object object, Supplier<T> call) {
return object != null ? call.get() : null;
}
public class Person {
private final String name;
Person(final String name) {
this.name = name;
}
String getName() {
return name;
}
}
}
编辑: 很抱歉提出一个重复的问题,我尝试搜索以前的答案,但显然使用了错误的搜索词。
我正在编辑问题,以补充说Seelenvirtuose提供的解决方案可以解决我的问题!
答案 0 :(得分:3)
来自JLS Sec 15.13.3(重点是我):
首先,如果方法引用表达式以ExpressionName或Primary开头,则将评估此子表达式。 如果子表达式的计算结果为null,则会引发NullPointerException ,并且方法引用表达式会突然完成。如果子表达式突然完成,则由于相同的原因,方法引用表达式也会突然完成。