在局部变量上调用的 Java 8 方法引用

标签 java lambda java-8 method-reference

我正在学习 Java 8,遇到了一些我觉得有点奇怪的东西。

考虑以下代码段:

private MyDaoClass myDao;

public void storeRelationships(Set<Relationship<ClassA, ClassB>> relationships) {
    RelationshipTransformer transformer = new RelationshipTransformerImpl();

    myDao.createRelationships(
            relationships.stream()
            .map((input) -> transformer.transformRelationship(input))
            .collect(Collectors.toSet())
    );
}

基本上,我需要将名为 relationships 的输入集映射到不同的类型,以便 符合我正在使用的 DAO 的 API。对于转换,我想使用我实例化为局部变量的现有 RelationshipTransformerImpl 类。

现在,这是我的问题:

如果我将上面的代码修改如下:

public void storeRelationships(Set<Relationship<ClassA, ClassB>> relationships) {
    RelationshipTransformer transformer = new RelationshipTransformerImpl();

    myDao.createRelationships(
            relationships.stream()
            .map((input) -> transformer.transformRelationship(input))
            .collect(Collectors.toSet())
    );

    transformer = null;  //setting the value of an effectively final variable
}

我显然会得到一个编译错误,因为局部变量 transformer 不再是“有效的最终”。但是,如果将 lambda 替换为方法引用:

public void storeRelationships(Set<Relationship<ClassA, ClassB>> relationships) {
    RelationshipTransformer transformer = new RelationshipTransformerImpl();

    myDao.createRelationships(
            relationships.stream()
            .map(transformer::transformRelationship)
            .collect(Collectors.toSet())
    );

    transformer = null;  //setting the value of an effectively final variable
}

然后我不再收到编译错误!为什么会这样?我认为编写 lambda 表达式的两种方式应该是等价的,但显然还有更多事情要做。

最佳答案

JLS 15.13.5可以解释一下:

The timing of method reference expression evaluation is more complex than that of lambda expressions (§15.27.4). When a method reference expression has an expression (rather than a type) preceding the :: separator, that subexpression is evaluated immediately. The result of evaluation is stored until the method of the corresponding functional interface type is invoked; at that point, the result is used as the target reference for the invocation. This means the expression preceding the :: separator is evaluated only when the program encounters the method reference expression, and is not re-evaluated on subsequent invocations on the functional interface type.

据我了解,由于在您的情况下 transformer 是::分隔符之前的表达式,因此它只计算一次并存储。由于不必为了调用引用的方法而重新计算它,所以以后将 transformer 分配为 null 并不重要。

关于在局部变量上调用的 Java 8 方法引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27747781/

相关文章:

java - Java中的类名约定

java - javadoc 中的枚举排序

java - Hibernate 在不删除旧元素的情况下将新元素保存在列表中

java - 作为 Executor 实现的方法引用

c++ - 如何对 unique_ptr 列表进行排序?

java - 如何在 Java 8 Stream API 中编写此循环

Java - 使用运行时运行curl命令被代理阻止

Java实现图形g?

java - 将两个对象列表合并到具有 Java 8 中不同对象值的 Map

java-8 - 流 API : Replace for-each loop (with expensive operation-call inside) with stream