Java Lambda 捕获还是重新执行?

Java Lambda capture or re execute?

制作函数式界面

@FunctionalInterface
public RulesFact {
    Object getPropertyValue(String propertyName);
}

方法中的 lambda 实例。

public RulesFact rulesFactImpl(Object o) {
    return propertyName->PropertyAccessorFactory.forBeanPropertyAccess(o).getPropertyValue(propertyName);
}

这个方法和上面的有区别吗?在上面的例子中,是否每次执行 lambda 时都会调用 PropertyAccessorFactory.forBeanPropertyAccess 方法?线程安全有区别吗?

public RulesFact rulesFactImpl(Object o) {
    BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(o);
    return propertyName->accessor.getPropertyValue(propertyName);
}

关于上述反射实用程序的 Javadoc:Package org.springframework.beans

假设这些 API 编写得相当好,有一点,但可能不是您关心的方式。

public RulesFact rulesFactImpl(Object o) {
  return propertyName->PropertyAccessorFactory.forBeanPropertyAccess(o).getPropertyValue(propertyName);
}

This returns a RulesFact 调用时调用 forBeanPropertyAccess 然后对其进行任何操作。如果多次调用它,它每次都会调用 forBeanPropertyAccess

public RulesFact rulesFactImpl(Object o) {
  BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(o);
  return propertyName->accessor.getPropertyValue(propertyName);
}

这会调用 forBeanPropertyAccess 一次并围绕其值进行关闭。你可以把这个闭包想象成一个实例变量。从某种意义上说,我们正在创建 RulesFact 的子类,它有一个名为 accessor 的实例变量,其值仅在构造时计算一次。如果我们多次调用这个 lambda,forBeanPropertyAccess 将永远不会被再次调用;它只会多次使用原始值。

调用RulesFact.getPropertyValue时执行lambda表达式。

这意味着第一个版本每次调用RulesFact.getPropertyValue时都会调用PropertyAccessorFactory.forBeanPropertyAccess(o),如果访问器可以随时间变化,这很好。

第二个版本在调用 rulesFactImpl 时调用 PropertyAccessorFactory.forBeanPropertyAccess(o),并缓存值,这对性能有好处,但如果访问者可以随时间变化则不好。

仅供参考:第二个版本可以使用方法参考:

public RulesFact rulesFactImpl(Object o) {
    BeanWrapper accessor = PropertyAccessorFactory.forBeanPropertyAccess(o);
    return accessor::getPropertyValue;
}

它或多或少相同,但在功能上并不相同。假设 PropertyAccessorFactory.forBeanPropertyAccess(o) 抛出异常。

在第一种情况下,rulesFactImpl(...) 永远不会抛出。只要 RulesFact.getPropertyValue 从未被调用过,就不会有例外。

在第二种情况下,rulesFactImpl(...) 总是会抛出。