J'ai le morceau de code suivant, qui utilise des interfaces fonctionnelles Java, qui compile, mais on ne sait pas pourquoi il compile:
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 {
}
Donc, ma confusion est à l’intérieur de la méthode main
:
updateManager.doUpdateForEach(it, DatabaseOperator::updateInfo);
UpdateManager#doUpdateForEach
attend un RecordIterator
(ok, est logique), et un FunctionalStuff
FunctionalStuff
a une seule méthode (évidemment), qui reçoit 2 paramètresdoUpdateForEach
est une référence de méthode (DatabaseOperator::updateInfo
)DatabaseOperator::updateInfo
reçoit un seul argumentcomment cela se compile-t-il? Comment la référence à la méthode DatabaseOperator::updateInfo
est-elle convertie dans l'interface fonctionnelle? Est-ce que je manque quelque chose d'évident? Ou est-ce un cas de coin d'interfaces fonctionnelles?
Comment la référence de la méthode
DatabaseOperator::updateInfo
est-elle convertie dans l'interface fonctionnelle?
La représentation lambda effective de votre référence de méthode est:
updateManager.doUpdateForEach(it, (databaseOperator, r) -> databaseOperator.updateInfo(r));
qui est une représentation supplémentaire de la classe anonyme:
new FunctionalStuff<MyRecord>() {
@Override
public void execute(DatabaseOperator databaseOperator, MyRecord r) throws Exception {
databaseOperator.updateInfo(r);
}
});
Tout d’abord, FunctionalStuff<T>
est défini comme ceci:
@FunctionalInterface
interface FunctionalStuff<T> {
void execute(final DatabaseOperator database, final T iterator) throws Exception;
}
La référence à la méthode DatabaseOperator::updateInfo
est convertie en une instance de FunctionalStuff<MyRecord>
comme celle-ci (j'ai laissé les types réels pour la suppression, mais ils peuvent être omis):
FunctionalStuff<MyRecord> func = (DatabaseOperator database, MyRecord r) -> database.updateInfo(r);
Ou si vous voulez l'utiliser comme classe anonyme:
FunctionalStuff<MyRecord> func = new FunctionalStuff<MyRecord>() {
void execute(final DatabaseOperator database, final MyRecord r) {
database.updateInfo(r);
}
}
Voir le tutorial avec l'exemple suivant:
Référence à une méthode d'instance d'un objet arbitraire d'un type particulier
Voici un exemple de référence à une méthode d'instance d'un objet arbitraire d'un type particulier:
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" }; Arrays.sort(stringArray, String::compareToIgnoreCase);
Expression lambda équivalente pour la référence de la méthode
String::compareToIgnoreCase
aurait la liste de paramètres formelle(String a, String b)
, oùa
etb
sont des noms arbitraires utilisés pour mieux décrire cet exemple. La référence à la méthode invoquerait le méthodea.compareToIgnoreCase(b)
.
Il existe 4 types de référence de méthode différents et vous utilisez Référence de méthode d'instance d'un objet d'un type particulier
À première vue, il ressemble à static method reference
qui est Class::staticType
mais il présente la différence suivante:
- 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.
Donc, dans votre cas, la méthode DatabaseOperator#updateInfo
est présente dans la classe DatabaseOperator
qui est identique au type DatabaseOperator
du premier argument de la méthode execute
dans l'interface fonctionnelle et le nombre d'arguments dans la méthode est égal à un de moins, car la référence this
est prise comme étant la valeur premier argument.
Si vous modifiez le paramètre DatabaseOperator # updateInfo pour qu'il prenne deux arguments, le compilateur affichera une erreur disant Cannot make a static reference to the non-static method updateInfo from the type DatabaseOperator
. Vous pouvez donc créer la méthode, à utiliser comme référence, statique ou vous devez utiliser new DatabaseOperator()#updateInfo
, qui sont deux autres types de référence de méthode en Java.