意外的 Java 功能接口转换

Unexpected Java Functional Interface conversion

我有以下代码,它使用 java 函数接口,可以编译,但不清楚为什么编译:

public class App {

    public static void main(String[] args) throws Exception {

        final RecordIterator it = new RecordIterator<MyRecord>();

        final UpdateManager updateManager = new UpdateManager();
        updateManager.doUpdateForEach(it, DatabaseOperator::updateInfo);

    }
}

class UpdateManager {

    public void doUpdateForEach(final RecordIterator recordIterator,
                                final FunctionalStuff<MyRecord> updateAction) throws Exception {

        updateAction.execute(new DatabaseOperator(), new MyRecord());

    }

}

class RecordIterator<E> {

}

@FunctionalInterface
interface FunctionalStuff<T> {

    void execute(final DatabaseOperator database, final T iterator) throws Exception;

}

class DatabaseOperator {

    public void updateInfo(final MyRecord r) {

    }

}

class MyRecord {

}

所以,我的困惑在于 main 方法:

这是如何编译的? DatabaseOperator::updateInfo方法引用是如何转化为函数式接口的?我错过了一些明显的东西吗?或者是功能接口的一些极端情况?

这不是 lambda 的实际工作方式,但本质上您可以看到

updateManager.doUpdateForEach(it, DatabaseOperator::updateInfo);

作为

DatabaseOperator referencedMethodOwner = instanceGivenAsMethodExpression;
updateManager.doUpdateForEach(it, 

    new FunctionalStuff{
        void execute(final T iterator) throws Exception{
            referencedMethodOwner.updateInfo(iterator)
       }
    });

How is the DatabaseOperator::updateInfo method reference converted into the functional interface?

您的方法引用的有效 lambda 表示是:

updateManager.doUpdateForEach(it, (databaseOperator, r) -> databaseOperator.updateInfo(r));

这是匿名的进一步表示 class:

new FunctionalStuff<MyRecord>() {
    @Override
    public void execute(DatabaseOperator databaseOperator, MyRecord r) throws Exception {
        databaseOperator.updateInfo(r);
    }
});

首先,FunctionalStuff<T>是这样定义的:

@FunctionalInterface
interface FunctionalStuff<T> {
    void execute(final DatabaseOperator database, final T iterator) throws Exception;
}

方法引用 DatabaseOperator::updateInfo 被转换为 FunctionalStuff<MyRecord> 的实例(为了清楚起见,我保留了实际类型,但可以省略):

FunctionalStuff<MyRecord> func = (DatabaseOperator database, MyRecord r) -> database.updateInfo(r);

或者如果您想将其用作匿名 class:

FunctionalStuff<MyRecord> func = new FunctionalStuff<MyRecord>() {
    void execute(final DatabaseOperator database, final MyRecord r) {
        database.updateInfo(r);
    }
}

参见 tutorial 示例:

Reference to an instance method of an arbitrary object of a particular type

The following is an example of a reference to an instance method of an arbitrary object of a particular type:

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).

有 4 种不同类型的方法参考,您正在使用 Instance method reference of an object of a particular type

乍一看它与 static method reference 相似,即 Class::staticType 但它有以下区别:

- the method should be present in the class same as type of first argument in functional interface
- The method used should have one less argument as opposed to number of arguments in the method declared in functional interface as the **this** reference is taken as first argument.

所以在你的情况下,方法 DatabaseOperator#updateInfo 存在于 DatabaseOperator class 中,它与 [=16= 的第一个参数的类型 DatabaseOperator 相同] 函数接口中的方法,并且方法中的参数数量少了一个,因为 this 引用被作为第一个参数。

如果您将 DatabaseOperator#updateInfo 更改为采用两个参数,则编译器将显示一条错误消息 Cannot make a static reference to the non-static method updateInfo from the type DatabaseOperator。因此,您可以将要用作参考的方法设为静态,或者您必须使用 new DatabaseOperator()#updateInfo,这是 java.

中另外两种类型的方法参考