J'ai lu dans des didacticiels que lors de l'utilisation de la référence de méthode, les arguments doivent être mis en correspondance dans la méthode et la méthode de l'interface fonctionnelle auxquelles nous faisons référence. Donc je reçois l'erreur suivante.
package com; public class Transaction { private int id; private int value; public Transaction(int id,int value) { this.id=id; this.value=value; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } } package com; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class MethodRefTest { public static void main(String[] args) { Transaction t1=new Transaction(1,20); Transaction t2=new Transaction(2,30); List<Transaction> list=new ArrayList<Transaction>(); list.add(t1); list.add(t2); List<Integer> intList=list.stream().map(Transaction::getId).collect(Collectors.toList()); System.out.println(intList); } }
Maintenant que j'ai compris pourquoi je reçois cette erreur Regardez l'extrait de code ci-dessous
public class MethodRefTest { public static void m1(int i) { System.out.println("Hey in method 1"); } public static void main(String[] args) { Runnable r=MethodRefTest::m1; //Compile time error } }
Dans la méthode map que j'ai utilisée, il accepte Function FunctionalInterface ... mais la référence de méthode que j'ai utilisée n'a aucun argument, mais la méthode apply (T t) de Function a un argument, et getId () n'a aucun argument, Dans ce cas, il ne renvoie aucune erreur même si les arguments ne correspondent pas.
Veuillez m'aider à comprendre cela?
3 Réponses :
mais la méthode apply (T t) de Function a un argument, et getId () n'a aucun argument
La fonction
apply
prend un argument comme un type de données et renvoie un autre type de données. Dans votre cas, c'est comme si:Consumer<Integer> consumer = MethodRefTest::m1La
Function
complète dans l'opérationmap
définit bien sûr l'entrée et le type de sortie de la transformation comme:new Function<Transaction, Integer>() { @Override public Integer apply(Transaction transaction) { return transaction.getId(); } }
Au contraire, dans votre code
m1
nécessite un argument de type entier à fournir à lui, ce qui entraînerait une sortievoid
. Par conséquent, votre implémentation correspond à unConsumer
et peut être représenté comme:public Integer apply(Transaction transaction) { return transaction.getId(); }
Pour vraiment créer un Runnable
, fournissez-lui une entrée comme Runnable r = () -> m1 (2); // en remplaçant 2 par une valeur entière
La référence de méthode
(Transaction t) -> t.getId()
est égale à expression lambda
Transaction::getId
Ce que vous pouvez voir accepter un argument Transaction
et renvoyer une valeur int
C'est une Function
Le compilateur Java est autorisé à faire correspondre une référence de méthode à une méthode non statique
avec n - 1 arguments comme si elle correspondait, avec l'objet lui-même comme premier argument. La section du JLS est 15.13.1 :
Sinon, étant donné un type de fonction ciblée avec les types de paramètres P 1 , ..., P n et un ensemble de méthodes potentiellement applicables, la déclaration à la compilation est sélectionné comme suit:
Si l'expression de référence de méthode a la forme ReferenceType :: [TypeArguments] Identifier , alors deux recherches pour une méthode applicable la plus spécifique sont effectuées. Chaque recherche est telle que spécifiée aux §15.12.2.2 à §15.12.2.5, avec les précisions ci-dessous. Chaque recherche produit un ensemble de méthodes applicables et, éventuellement, désigne une méthode la plus spécifique de l'ensemble. En cas d'erreur comme spécifié au §15.12.2.4, l'ensemble des méthodes applicables est vide. Dans le cas d'une erreur comme spécifié au §15.12.2.5, il n'y a pas de méthode la plus spécifique.
Lors de la première recherche, la référence de méthode est traitée comme s'il s'agissait d'un appel avec des expressions d'argument de types P 1 , ..., P n . Les arguments de type, le cas échéant, sont donnés par l'expression de référence de méthode.
Dans la deuxième recherche, si P 1 , ..., P n n'est pas vide et P 1 est un sous-type de < em> ReferenceType , alors l'expression de référence de méthode est traitée comme s'il s'agissait d'une expression d'invocation de méthode avec des expressions d'argument de types P 2 , ..., P n sub >.
Si la première recherche produit une méthode plus spécifique qui est
statique
et que l'ensemble des méthodes applicables produit par la deuxième recherche ne contient aucune méthode nonstatique
, alors le La déclaration à la compilation est la méthode la plus spécifiée de la première recherche.Sinon, si l'ensemble des méthodes applicables produit par la première recherche ne contient aucune méthode
statique
et que la deuxième recherche produit une méthode plus spécifique qui n'est passtatique
, alors la déclaration à la compilation est la méthode la plus spécifique de la deuxième recherche.
La "première recherche" est la correspondance directe des paramètres de méthode avec un type d'interface fonctionnelle. La "deuxième recherche" ajoute une certaine flexibilité en ce que l'instance d'objet elle-même à partir d'une référence de méthode peut servir de premier paramètre correspondant à une interface fonctionnelle.
Dans votre exemple principal, la méthode m1
est statique
et aucune instance ne peut être implicitement le premier argument, donc la "deuxième recherche" ne s'applique pas ici.
Dans l'exemple du bas, le getId
n'est pas statique, et la "deuxième recherche" ci-dessus s'applique. Ici, getId
n'a pas d'arguments, donc l'ensemble de paramètres "P2-Pn" est vide. Cependant, l'objet lui-même est le premier argument implicite, il correspond donc à la signature fonctionnelle Function
attendue par la méthode map
dans Stream code >.