意外的 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
方法:
- main方法的最后一行是
updateManager.doUpdateForEach(it, DatabaseOperator::updateInfo);
UpdateManager#doUpdateForEach
方法需要一个 RecordIterator
(好的,有道理)和一个 FunctionalStuff
FunctionalStuff
有一个方法(很明显),它接收 2 个参数
doUpdateForEach
的第二个参数是方法引用 (DatabaseOperator::updateInfo
)
DatabaseOperator::updateInfo
方法接收单个参数
这是如何编译的? 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.
中另外两种类型的方法参考
我有以下代码,它使用 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
方法:
- main方法的最后一行是
updateManager.doUpdateForEach(it, DatabaseOperator::updateInfo);
UpdateManager#doUpdateForEach
方法需要一个RecordIterator
(好的,有道理)和一个FunctionalStuff
FunctionalStuff
有一个方法(很明显),它接收 2 个参数doUpdateForEach
的第二个参数是方法引用 (DatabaseOperator::updateInfo
)DatabaseOperator::updateInfo
方法接收单个参数
这是如何编译的? 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)
, wherea
andb
are arbitrary names used to better describe this example. The method reference would invoke the methoda.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.