意外的Java功能接口转换

时间:2018-12-27 12:00:50

标签: java java-8 functional-interface

我有下面的代码,它们使用java Functional Interfaces进行编译,但是不清楚为什么编译:

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方法的内部:

  • main方法的最后一行是updateManager.doUpdateForEach(it, DatabaseOperator::updateInfo);
  • UpdateManager#doUpdateForEach方法需要一个RecordIterator(好的,很合理)和一个FunctionalStuff
  • FunctionalStuff有一个方法(显然),可以接收2个参数
  • doUpdateForEach的第二个参数是方法引用(DatabaseOperator::updateInfo
  • DatabaseOperator::updateInfo方法只接收一个参数

如何编译? DatabaseOperator::updateInfo方法引用如何转换为功能接口?我是否缺少明显的东西?还是功能接口有些特殊情况?

4 个答案:

答案 0 :(得分:7)

  

如何转换dfc= df.groupby(['Identification_person']).Day.nunique().reset_index() 方法参考   进入功能界面?

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

DatabaseOperator::updateInfo

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

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

答案 1 :(得分:2)

首先,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);

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

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

通过以下示例查看tutorial

  

引用特定类型的任意对象的实例方法

     

以下是对一个实例方法的引用示例   特定类型的任意对象:

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

等效lambda表达式,供方法参考   String::compareToIgnoreCase将具有正式的参数列表   (String a, String b),其中ab是用于   更好地描述这个例子。方法参考将调用   方法a.compareToIgnoreCase(b)

答案 2 :(得分:0)

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

现在乍一看,它类似于static method reference的{​​{1}},但有以下区别:

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方法的第一个参数的类型DatabaseOperator相同该方法中的参数个数要少一些,因为将execute引用作为第一个参数。

如果将DatabaseOperator#updateInfo更改为采用两个参数,则编译器将显示错误this。因此,您可以将要用作引用的方法设为静态,或者必须使用Cannot make a static reference to the non-static method updateInfo from the type DatabaseOperator这是Java中另外两种方法引用。

答案 3 :(得分:-2)

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

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

DatabaseOperator referencedMethodOwner = instanceGivenAsMethodExpression;
updateManager.doUpdateForEach(it, 

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