【发布时间】:2019-05-13 13:16:01
【问题描述】:
我的印象是下面的 lambda 表达式
() -> object.method()
相当于方法引用
object::method
IntelliJ 使情况更加复杂,它一直在唠叨我用后者替换前者。
但是,我偶然发现了一个似乎并非如此的案例。我有一些代码需要访问各种 bean 的许多属性,这些属性可能为空,也可能不为空。因为我不想写一大堆
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 不为空时,其行为完全相同。但是,如果这些 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 提供的解决方案解决了我的问题!
【问题讨论】:
-
附带说明:更好的方法是使用方法
<O, T> T nullSafeGet(O object, Function<O, T> function) { return object != null ? function.apply(object) : null; }并使用assertNull(nullSafeGet(person, Person::getName));调用它。
标签: java lambda lazy-evaluation