【问题标题】:Method reference not evaluated lazily? [duplicate]方法参考没有懒惰地评估? [复制]
【发布时间】: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 提供的解决方案解决了我的问题!

【问题讨论】:

  • 附带说明:更好的方法是使用方法&lt;O, T&gt; T nullSafeGet(O object, Function&lt;O, T&gt; function) { return object != null ? function.apply(object) : null; } 并使用assertNull(nullSafeGet(person, Person::getName)); 调用它。

标签: java lambda lazy-evaluation


【解决方案1】:

来自JLS Sec 15.13.3(强调我的):

首先,如果方法引用表达式以 ExpressionName 或 Primary 开头,则计算此子表达式。 如果子表达式的计算结果为 null,则会引发 NullPointerException,并且方法引用表达式会突然完成。如果子表达式突然完成,则方法引用表达式出于同样的原因突然完成。

【讨论】:

    猜你喜欢
    • 2014-10-10
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 2012-12-07
    • 2017-01-13
    • 2019-01-07
    • 1970-01-01
    • 2016-05-12
    相关资源
    最近更新 更多