J'explorais la source Java 8 et j'ai trouvé cette partie du code très surprenante:
//defined in IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
return evaluate(ReduceOps.makeInt(op));
}
@Override
public final OptionalInt max() {
return reduce(Math::max); //this is the gotcha line
}
//defined in Math.java
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
Est-ce Math::max
quelque chose comme un pointeur de méthode? Comment static
convertit une méthode normale enIntBinaryOperator
?
TestingLambda$$Lambda$2/8460669
etTestingLambda$$Lambda$3/11043253
ont été créés sur deux invocations.Réponses:
Habituellement, on appellerait la
reduce
méthode en utilisantMath.max(int, int)
comme suit:Cela nécessite beaucoup de syntaxe pour simplement appeler
Math.max
. C'est là que les expressions lambda entrent en jeu. Depuis Java 8, il est autorisé de faire la même chose de manière beaucoup plus courte:Comment cela marche-t-il? Le compilateur java "détecte", que vous souhaitez implémenter une méthode qui accepte deux
int
s et en renvoie unint
. Cela équivaut aux paramètres formels de la seule et unique méthode d'interfaceIntBinaryOperator
(le paramètre de méthodereduce
vous souhaitez appeler). Donc, le compilateur fait le reste pour vous - il suppose simplement que vous voulez implémenterIntBinaryOperator
.Mais comme
Math.max(int, int)
elle-même satisfait aux exigences formelles deIntBinaryOperator
, elle peut être utilisée directement. Étant donné que Java 7 n'a pas de syntaxe permettant de passer une méthode elle-même comme argument (vous ne pouvez transmettre que les résultats de méthode, mais jamais les références de méthode), la::
syntaxe a été introduite dans Java 8 pour référencer les méthodes:Notez que cela sera interprété par le compilateur, pas par la JVM lors de l'exécution! Bien qu'il produise des bytecodes différents pour les trois extraits de code, ils sont sémantiquement égaux, donc les deux derniers peuvent être considérés comme des versions courtes (et probablement plus efficaces) de l'
IntBinaryOperator
implémentation ci-dessus!(Voir aussi Traduction des expressions Lambda )
la source
::
est appelé référence de méthode. Il s'agit essentiellement d'une référence à une seule méthode. C'est-à-dire qu'il fait référence à une méthode existante par son nom.Brève explication :
Voici un exemple de référence à une méthode statique:
square
peut être transmis comme des références d'objet et déclenché en cas de besoin. En fait, il peut tout aussi bien être utilisé comme référence à des méthodes "normales" d'objets questatic
celles. Par exemple:Function
ci-dessus est une interface fonctionnelle . Pour bien comprendre::
, il est également important de comprendre les interfaces fonctionnelles. En clair, une interface fonctionnelle est une interface avec une seule méthode abstraite.Des exemples d'interfaces fonctionnelles comprennent
Runnable
,Callable
etActionListener
.Function
ci - dessus est une interface fonctionnelle avec une seule méthode:apply
. Il prend un argument et produit un résultat.La raison pour laquelle les
::
s sont géniaux est que :Par exemple, au lieu d'écrire le corps lambda
Vous pouvez simplement faire
Au moment de l'exécution, ces deux
square
méthodes se comportent exactement de la même manière l'une que l'autre. Le bytecode peut être ou ne pas être le même (bien que, dans le cas ci-dessus, le même bytecode soit généré; compilez ce qui précède et vérifiez avecjavap -c
).Le seul critère majeur à satisfaire est: la méthode que vous fournissez doit avoir une signature similaire à la méthode de l'interface fonctionnelle que vous utilisez comme référence d'objet .
Ce qui suit est illégal:
square
attend un argument et retourne adouble
. Laget
méthode de Supplier renvoie une valeur mais ne prend pas d'argument. Par conséquent, cela entraîne une erreur.Une référence de méthode fait référence à la méthode d'une interface fonctionnelle. (Comme mentionné, les interfaces fonctionnelles ne peuvent avoir qu'une seule méthode chacune).
Quelques exemples supplémentaires: la
accept
méthode dans Consumer prend une entrée mais ne renvoie rien.Ci-dessus,
getRandom
ne prend aucun argument et renvoie adouble
. Ainsi, toute interface fonctionnelle qui satisfait aux critères de: prendre aucun argument et retournerdouble
peut être utilisée.Un autre exemple:
En cas de types paramétrés :
Les références de méthode peuvent avoir différents styles, mais fondamentalement, elles signifient toutes la même chose et peuvent simplement être visualisées comme des lambdas:
ClassName::methName
)instanceRef::methName
)super::methName
)ClassName::methName
)ClassName::new
)TypeName[]::new
)Pour plus d'informations, voir http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html .
la source
Oui c'est vrai. L'
::
opérateur est utilisé pour le référencement de méthode. Ainsi, on peut extraire des méthodes statiques des classes en l'utilisant ou des méthodes d'objets. Le même opérateur peut être utilisé même pour les constructeurs. Tous les cas mentionnés ici sont illustrés dans l'exemple de code ci-dessous.La documentation officielle d'Oracle est disponible ici .
Vous pouvez avoir un meilleur aperçu des modifications du JDK 8 dans cet article. Dans la section de référence Méthode / Constructeur , un exemple de code est également fourni:
la source
method(Math::max);
est l'invocation et la définition de la méthode serait commepublic static void method(IntBinaryOperator op){System.out.println(op.applyAsInt(1, 2));}
. Voilà comment son utilisé.Cela semble un peu tard mais voici mes deux cents. Une expression lambda est utilisée pour créer des méthodes anonymes. Il ne fait qu'appeler une méthode existante, mais il est plus clair de se référer directement à la méthode par son nom. Et la référence de méthode nous permet de le faire en utilisant l'opérateur de référence de méthode
::
.Considérez la classe simple suivante où chaque employé a un nom et un grade.
Supposons que nous ayons une liste d'employés renvoyés par une certaine méthode et que nous voulons trier les employés par leur grade. Nous savons que nous pouvons utiliser la classe anonyme comme:
où getDummyEmployee () est une méthode comme:
Nous savons maintenant que le comparateur est une interface fonctionnelle. Une interface fonctionnelle est celle avec exactement une méthode abstraite (bien qu'elle puisse contenir une ou plusieurs méthodes par défaut ou statiques). L'expression lambda fournit l'implémentation de
@FunctionalInterface
sorte qu'une interface fonctionnelle ne peut avoir qu'une seule méthode abstraite. Nous pouvons utiliser l'expression lambda comme:Cela semble bien, mais que se passe-t-il si la classe
Employee
fournit également une méthode similaire:Dans ce cas, l'utilisation du nom de la méthode lui-même sera plus claire. Par conséquent, nous pouvons nous référer directement à la méthode en utilisant la référence de méthode comme:
Selon les documents, il existe quatre types de références de méthode:
la source
::
est un nouvel opérateur inclus dans Java 8 qui est utilisé pour référencer une méthode d'une classe existante. Vous pouvez référencer des méthodes statiques et des méthodes non statiques d'une classe.Pour référencer des méthodes statiques, la syntaxe est:
Pour référencer des méthodes non statiques, la syntaxe est
Et
La seule condition préalable pour référencer une méthode est que cette méthode existe dans une interface fonctionnelle, qui doit être compatible avec la référence de la méthode.
Les références de méthode, une fois évaluées, créent une instance de l'interface fonctionnelle.
Trouvé sur: http://www.speakingcs.com/2014/08/method-references-in-java-8.html
la source
Il s'agit d'une référence de méthode en Java 8. La documentation Oracle est ici .
Comme indiqué dans la documentation ...
la source
:: Operator a été introduit en java 8 pour les références de méthode. Une référence de méthode est la syntaxe abrégée d'une expression lambda qui exécute une seule méthode. Voici la syntaxe générale d'une référence de méthode:
Nous savons que nous pouvons utiliser des expressions lambda au lieu d'utiliser une classe anonyme. Mais parfois, l'expression lambda n'est en fait qu'un appel à une méthode, par exemple:
Pour rendre le code plus clair, vous pouvez transformer cette expression lambda en référence de méthode:
la source
Le :: est connu comme référence de méthode. Disons que nous voulons appeler une méthode de calcul de prix de la classe Purchase. Ensuite, nous pouvons l'écrire comme:
Il peut également être considéré comme une forme courte d'écriture de l'expression lambda car les références de méthode sont converties en expressions lambda.
la source
J'ai trouvé cette source très intéressante.
En fait, c'est la Lambda qui se transforme en double colon . Le Double Colon est plus lisible. Nous suivons ces étapes:
ÉTAPE 1:
ÉTAPE 2:
ÉTAPE 3:
la source
Person::getAge()
devrait l'êtrePerson::getAge
.return reduce(Math::max);
n'est pas égal àreturn reduce(max());
Mais cela signifie quelque chose comme ça:
Vous pouvez simplement enregistrer 47 touches si vous écrivez comme ceci
la source
Étant donné que de nombreuses réponses ici expliquent bien le
::
comportement, je tiens également à préciser que l'::
opérateur n'a pas besoin d'avoir exactement la même signature que l'interface fonctionnelle de référence si elle est utilisée pour des variables d'instance . Supposons que nous avons besoin d'un BinaryOperator qui a le type de TestObject . De manière traditionnelle, sa mise en œuvre comme ceci:Comme vous le voyez dans l'implémentation anonyme, il nécessite deux arguments TestObject et renvoie également un objet TestObject. Pour satisfaire cette condition en utilisant l'
::
opérateur, nous pouvons commencer avec une méthode statique:puis appelez:
Ok, ça s'est bien compilé. Et si nous avons besoin d'une méthode d'instance? Permet de mettre à jour TestObject avec la méthode d'instance:
Maintenant, nous pouvons accéder à l'instance comme ci-dessous:
Ce code se compile bien, mais en dessous d'un pas:
Mon éclipse me dit "Impossible de faire une référence statique à la méthode non statique testInstance (TestObject, TestObject) du type TestObject ..."
Assez juste, c'est une méthode d'instance, mais si nous surcharge
testInstance
comme ci-dessous:Et appelez:
Le code se compilera très bien. Parce qu'il appellera
testInstance
avec un seul paramètre au lieu d'un double. Ok alors qu'est-il arrivé à nos deux paramètres? Permet d'imprimer et de voir:Qui produira:
Ok donc JVM est assez intelligent pour appeler param1.testInstance (param2). Peut-on utiliser
testInstance
une autre ressource mais pas TestObject, c'est-à-dire:Et appelez:
Il ne compilera tout simplement pas et le compilateur dira: "Le type TestUtil ne définit pas testInstance (TestObject, TestObject)" . Le compilateur recherchera donc une référence statique s'il ne s'agit pas du même type. Et le polymorphisme? Si nous supprimons les derniers modificateurs et ajoutons notre classe SubTestObject :
Et appelez:
Il ne compilera pas aussi bien, le compilateur cherchera toujours une référence statique. Mais le code ci-dessous se compilera très bien car il passe un test is-a:
la source
Dans java-8 Streams Reducer dans les travaux simples est une fonction qui prend deux valeurs en entrée et renvoie le résultat après un certain calcul. ce résultat est alimenté lors de la prochaine itération.
dans le cas de la fonction Math: max, la méthode continue de renvoyer au maximum deux valeurs passées et, à la fin, vous avez le plus grand nombre en main.
la source
Au moment de l'exécution, ils se comportent exactement de la même manière.
Au moment de l'exécution, ils se comportent exactement de la même manière.method (math :: max) ;, il génère les mêmes mathématiques (se conformer ci-dessus et vérifier javap -c;))
la source
Dans les anciennes versions de Java, au lieu de "::" ou lambd, vous pouvez utiliser:
Ou en passant à la méthode:
la source
Donc , je vois ici des tonnes de réponses qui sont franchement trop compliquées, et c'est un euphémisme.
La réponse est assez simple: :: cela s'appelle une référence de méthode https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
Je ne vais donc pas copier-coller, sur le lien, vous pouvez trouver toutes les informations si vous faites défiler le tableau.
Voyons maintenant ce qu'est une référence de méthode:
A :: B remplace quelque peu l' expression lambda en ligne suivante : (params ...) -> AB (params ...)
Pour corréler cela avec vos questions, il est nécessaire de comprendre une expression java lambda. Ce qui n'est pas difficile.
Une expression lambda en ligne est similaire à une interface fonctionnelle définie (qui est une interface qui n'a ni plus ni moins d'une méthode) . Jetons un coup d'œil à ce que je veux dire:
InterfaceX doit être une interface fonctionnelle. Toute interface fonctionnelle, la seule chose importante à propos d'InterfaceX pour ce compilateur est que vous définissez le format:
InterfaceX peut être n'importe lequel de ces éléments:
ou ca
ou plus générique:
Prenons le premier cas présenté et l'expression lambda en ligne que nous avons définie précédemment.
Avant Java 8, vous auriez pu le définir de la même manière:
Fonctionnellement, c'est la même chose. La différence réside davantage dans la façon dont le compilateur perçoit cela.
Maintenant que nous avons examiné l'expression lambda en ligne, revenons aux références de méthode (: :). Disons que vous avez une classe comme celle-ci:
Étant donné que la méthode anyFunctions a les mêmes types que InterfaceX callMe , nous pouvons les assimiler avec une référence de méthode.
Nous pouvons l'écrire comme ceci:
et cela équivaut à ceci:
Une chose intéressante et un avantage des références de méthode sont qu'au début, jusqu'à ce que vous les affectiez à des variables, elles sont sans type. Vous pouvez donc les transmettre en tant que paramètres à n'importe quelle interface fonctionnelle équivalente (ayant les mêmes types définis). C'est exactement ce qui se passe dans votre cas
la source
Les réponses précédentes sont assez complètes concernant ce
::
fait la référence de méthode. Pour résumer, il fournit un moyen de faire référence à une méthode (ou constructeur) sans l'exécuter, et lorsqu'il est évalué, il crée une instance de l'interface fonctionnelle qui fournit le contexte de type cible.Vous trouverez ci-dessous deux exemples pour trouver un objet avec la valeur maximale dans un
ArrayList
avec et SANS l'utilisation de la::
référence de méthode. Des explications se trouvent dans les commentaires ci-dessous.SANS l'utilisation de
::
AVEC l'utilisation de
::
la source
L'
::
opérateur double colon ie est introduit dans Java 8 comme référence de méthode . La référence de méthode est une forme d' expression lambda qui est utilisée pour référencer la méthode existante par son nom.classname :: methodName
ex:-
stream.forEach(element -> System.out.println(element))
En utilisant Double Colon
::
stream.forEach(System.out::println(element))
la source