:: Opérateur (double point) dans Java 8

956

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::maxquelque chose comme un pointeur de méthode? Comment staticconvertit une méthode normale enIntBinaryOperator ?

Narendra Pathai
la source
60
C'est du sucre syntaxique d'avoir les implémentations d'interface de génération automatique du compilateur en fonction de la fonction que vous fournissez (pour rendre le truc lambda plus facile à utiliser avec les bases de code existantes).
Neet
4
java.dzone.com/articles/java-lambda-expressions-vs pourrait aider, n'a pas approfondi le sujet
Pontus Backlund
8
@Neet ce n'est pas exactement du "sucre syntaxique", sauf si vous pouvez dire pour quoi. c'est-à-dire "x est le sucre syntaxique pour y".
Ingo
6
@Ingo crée un nouvel objet lambda chaque fois que je l'utilise. TestingLambda$$Lambda$2/8460669et TestingLambda$$Lambda$3/11043253ont été créés sur deux invocations.
Narendra Pathai du
13
Les lambdas et les références de méthode ne sont pas des "anciennes classes internes anonymes". Voir programmers.stackexchange.com/a/181743/59134 . Oui, si nécessaire, de nouvelles classes et instances sont créées à la volée, si nécessaire, mais uniquement si nécessaire.
Stuart marque

Réponses:

1024

Habituellement, on appellerait la reduceméthode en utilisant Math.max(int, int)comme suit:

reduce(new IntBinaryOperator() {
    int applyAsInt(int left, int right) {
        return Math.max(left, right);
    }
});

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:

reduce((int left, int right) -> Math.max(left, right));

Comment cela marche-t-il? Le compilateur java "détecte", que vous souhaitez implémenter une méthode qui accepte deux ints et en renvoie un int. Cela équivaut aux paramètres formels de la seule et unique méthode d'interface IntBinaryOperator(le paramètre de méthodereduce vous souhaitez appeler). Donc, le compilateur fait le reste pour vous - il suppose simplement que vous voulez implémenter IntBinaryOperator.

Mais comme Math.max(int, int)elle-même satisfait aux exigences formelles de IntBinaryOperator, 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:

reduce(Math::max);

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' IntBinaryOperatorimplémentation ci-dessus!

(Voir aussi Traduction des expressions Lambda )

isnot2bad
la source
489

::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:

class Hey {
     public static double square(double num){
        return Math.pow(num, 2);
    }
}

Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);

squarepeut ê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 que staticcelles. Par exemple:

class Hey {
    public double square(double num) {
        return Math.pow(num, 2);
    }
}

Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);

Functionci-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, Callableet ActionListener.

Functionci - 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 :

Les références de méthode sont des expressions qui ont le même traitement que les expressions lambda (...), mais au lieu de fournir un corps de méthode, elles font référence à une méthode existante par son nom.

Par exemple, au lieu d'écrire le corps lambda

Function<Double, Double> square = (Double x) -> x * x;

Vous pouvez simplement faire

Function<Double, Double> square = Hey::square;

Au moment de l'exécution, ces deux squaremé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 avec javap -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:

Supplier<Boolean> p = Hey::square; // illegal

squareattend un argument et retourne a double. La getmé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 acceptméthode dans Consumer prend une entrée mais ne renvoie rien.

Consumer<Integer> b1 = System::exit;   // void exit(int status)
Consumer<String[]> b2 = Arrays::sort;  // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)

class Hey {
    public double getRandom() {
        return Math.random();
    }
}

Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result

Ci-dessus, getRandomne prend aucun argument et renvoie a double. Ainsi, toute interface fonctionnelle qui satisfait aux critères de: prendre aucun argument et retournerdouble peut être utilisée.

Un autre exemple:

Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");

En cas de types paramétrés :

class Param<T> {
    T elem;
    public T get() {
        return elem;
    }

    public void set(T elem) {
        this.elem = elem;
    }

    public static <E> E returnSame(E elem) {
        return elem;
    }
}

Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;

Function<String, String> func = Param::<String>returnSame;

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:

  1. Une méthode statique ( ClassName::methName)
  2. Une méthode d'instance d'un objet particulier ( instanceRef::methName)
  3. Une super méthode d'un objet particulier ( super::methName)
  4. Une méthode d'instance d'un objet arbitraire d'un type particulier ( ClassName::methName)
  5. Une référence de constructeur de classe ( ClassName::new)
  6. Une référence de constructeur de tableau ( TypeName[]::new)

Pour plus d'informations, voir http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html .

Jatin
la source
6
Merci pour l'explication. En résumé: '::' à utiliser pour extraire une méthode qui satisfait une FunctionalInterface (lambda): ClassX :: staticMethodX, ou instanceX :: instanceMethodX "
jessarah
55

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:

interface ConstructorReference {
    T constructor();
}

interface  MethodReference {
   void anotherMethod(String input);
}

public class ConstructorClass {
    String value;

   public ConstructorClass() {
       value = "default";
   }

   public static void method(String input) {
      System.out.println(input);
   }

   public void nextMethod(String input) {
       // operations
   }

   public static void main(String... args) {
       // constructor reference
       ConstructorReference reference = ConstructorClass::new;
       ConstructorClass cc = reference.constructor();

       // static method reference
       MethodReference mr = cc::method;

       // object method reference
       MethodReference mr2 = cc::nextMethod;

       System.out.println(cc.value);
   }
}
Olimpiu POP
la source
une bonne explication est celle trouvée ici: doanduyhai.wordpress.com/2012/07/14/…
Olimpiu POP
1
@RichardTingle method(Math::max);est l'invocation et la définition de la méthode serait comme public static void method(IntBinaryOperator op){System.out.println(op.applyAsInt(1, 2));}. Voilà comment son utilisé.
Narendra Pathai
2
Pour ceux qui connaissent C #, il est similaire à DelegateType d = new DelegateType (MethodName);
Adrian Zanescu
27

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.

public class Employee {
    private String name;
    private String grade;

    public Employee(String name, String grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = 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:

    List<Employee> employeeList = getDummyEmployees();

    // Using anonymous class
    employeeList.sort(new Comparator<Employee>() {
           @Override
           public int compare(Employee e1, Employee e2) {
               return e1.getGrade().compareTo(e2.getGrade());
           }
    });

où getDummyEmployee () est une méthode comme:

private static List<Employee> getDummyEmployees() {
        return Arrays.asList(new Employee("Carrie", "C"),
                new Employee("Fanishwar", "F"),
                new Employee("Brian", "B"),
                new Employee("Donald", "D"),
                new Employee("Adam", "A"),
                new Employee("Evan", "E")
                );
    }

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 @FunctionalInterfacesorte qu'une interface fonctionnelle ne peut avoir qu'une seule méthode abstraite. Nous pouvons utiliser l'expression lambda comme:

employeeList.sort((e1,e2) -> e1.getGrade().compareTo(e2.getGrade())); // lambda exp

Cela semble bien, mais que se passe-t-il si la classe Employeefournit également une méthode similaire:

public class Employee {
    private String name;
    private String grade;
    // getter and setter
    public static int compareByGrade(Employee e1, Employee e2) {
        return e1.grade.compareTo(e2.grade);
    }
}

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:

employeeList.sort(Employee::compareByGrade); // method reference

Selon les documents, il existe quatre types de références de méthode:

+----+-------------------------------------------------------+--------------------------------------+
|    | Kind                                                  | Example                              |
+----+-------------------------------------------------------+--------------------------------------+
| 1  | Reference to a static method                          | ContainingClass::staticMethodName    |
+----+-------------------------------------------------------+--------------------------------------+
| 2  |Reference to an instance method of a particular object | containingObject::instanceMethodName | 
+----+-------------------------------------------------------+--------------------------------------+
| 3  | Reference to an instance method of an arbitrary object| ContainingType::methodName           |
|    | of a particular type                                  |                                      |  
+----+-------------------------------------------------------+--------------------------------------+
| 4  |Reference to a constructor                             | ClassName::new                       |
+------------------------------------------------------------+--------------------------------------+
akhil_mittal
la source
25

::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:

ClassName :: methodName 

Pour référencer des méthodes non statiques, la syntaxe est

objRef :: methodName

Et

ClassName :: methodName

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

sreenath
la source
22

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 référence de méthode Person :: compareByAge est une référence à une méthode statique.

Voici un exemple de référence à une méthode d'instance d'un objet particulier:

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName); 

La méthode référence myComparisonProvider :: compareByName appelle la méthode compareByName qui fait partie de l'objet myComparisonProvider. Le JRE déduit les arguments de type de méthode, qui dans ce cas sont (Person, Person).

david99world
la source
2
mais la méthode 'compareByAge' n'est pas statique.
abbas
3
@abbas n'est pas non plus compareByName. Par conséquent, vous accédez à ces méthodes non statiques via l'opérateur de référence à l'aide d'un objet. S'ils étaient statiques, vous pourriez utiliser le nom de classe comme ComparisionProvider :: someStaticMethod
Seshadri R
6

:: 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:

Object :: methodName

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:

Consumer<String> c = s -> System.out.println(s);

Pour rendre le code plus clair, vous pouvez transformer cette expression lambda en référence de méthode:

Consumer<String> c = System.out::println;
Vaibhav9518
la source
3

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:

Purchase::calculatePrice

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.

Sonu
la source
Puis-je créer des références de méthode imbriquées? par exemple groupingBy (Order :: customer :: name)
vous ne pouvez pas faire une référence de méthode imbriquée de cette façon
Kirby
3

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:

// We create a comparator of two persons
Comparator c = (Person p1, Person p2) -> p1.getAge().compareTo(p2.getAge());

ÉTAPE 2:

// We use the interference
Comparator c = (p1, p2) -> p1.getAge().compareTo(p2.getAge());

ÉTAPE 3:

// The magic using method reference
Comparator c = Comparator.comparing(Person::getAge);
Houssem Badri
la source
3
On dirait que ça Person::getAge()devrait l'être Person::getAge.
Qwertiy
2

return reduce(Math::max);n'est pas égal àreturn reduce(max());

Mais cela signifie quelque chose comme ça:

IntBinaryOperator myLambda = (a, b)->{(a >= b) ? a : b};//56 keystrokes I had to type -_-
return reduce(myLambda);

Vous pouvez simplement enregistrer 47 touches si vous écrivez comme ceci

return reduce(Math::max);//Only 9 keystrokes ^_^
Jude Niroshan
la source
2

É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:

BinaryOperator<TestObject> binary = new BinaryOperator<TestObject>() {

        @Override
        public TestObject apply(TestObject t, TestObject u) {

            return t;
        }
    };

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:

public class TestObject {


    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

puis appelez:

BinaryOperator<TestObject> binary = TestObject::testStatic;

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:

public class TestObject {

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Maintenant, nous pouvons accéder à l'instance comme ci-dessous:

TestObject testObject = new TestObject();
BinaryOperator<TestObject> binary = testObject::testInstance;

Ce code se compile bien, mais en dessous d'un pas:

BinaryOperator<TestObject> binary = TestObject::testInstance;

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 testInstancecomme ci-dessous:

public class TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Et appelez:

BinaryOperator<TestObject> binary = TestObject::testInstance;

Le code se compilera très bien. Parce qu'il appellera testInstanceavec 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:

public class TestObject {

    public TestObject() {
        System.out.println(this.hashCode());
    }

    public final TestObject testInstance(TestObject t){
        System.out.println("Test instance called. this.hashCode:" 
    + this.hashCode());
        System.out.println("Given parameter hashCode:" + t.hashCode());
        return t;
    }

    public final TestObject testInstance(TestObject t, TestObject t2){
        return t;
    }

    public static final TestObject testStatic(TestObject t, TestObject t2){
        return t;
    }
}

Qui produira:

 1418481495  
 303563356  
 Test instance called. this.hashCode:1418481495
 Given parameter hashCode:303563356

Ok donc JVM est assez intelligent pour appeler param1.testInstance (param2). Peut-on utiliser testInstanceune autre ressource mais pas TestObject, c'est-à-dire:

public class TestUtil {

    public final TestObject testInstance(TestObject t){
        return t;
    }
}

Et appelez:

BinaryOperator<TestObject> binary = TestUtil::testInstance;

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 :

public class SubTestObject extends TestObject {

    public final TestObject testInstance(TestObject t){
        return t;
    }

}

Et appelez:

BinaryOperator<TestObject> binary = SubTestObject::testInstance;

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:

public class TestObject {

    public SubTestObject testInstance(Object t){
        return (SubTestObject) t;
    }

}

BinaryOperator<TestObject> binary = TestObject::testInstance;

* Je suis juste en train d'étudier donc j'ai compris en essayant de voir, n'hésitez pas à me corriger si je me trompe

HRgiger
la source
2

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.

Pramod
la source
1

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;))

Alfa khatoon
la source
1

Dans les anciennes versions de Java, au lieu de "::" ou lambd, vous pouvez utiliser:

public interface Action {
    void execute();
}

public class ActionImpl implements Action {

    @Override
    public void execute() {
        System.out.println("execute with ActionImpl");
    }

}

public static void main(String[] args) {
    Action action = new Action() {
        @Override
        public void execute() {
            System.out.println("execute with anonymous class");
        }
    };
    action.execute();

    //or

    Action actionImpl = new ActionImpl();
    actionImpl.execute();
}

Ou en passant à la méthode:

public static void doSomething(Action action) {
    action.execute();
}
Kamil Tomasz Jarmusik
la source
1

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 f = (x) -> x*x; 

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:

interface InterfaceX
{
    public Integer callMe(Integer x);
}

ou ca

interface InterfaceX
{
    public Double callMe(Integer x);
}

ou plus générique:

interface InterfaceX<T,U>
{
    public T callMe(U x);
}

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:

 InterfaceX o = new InterfaceX(){
                     public int callMe (int x, int y) 
                       {
                        return x*x;
                       } };

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:

class Q {
        public static int anyFunction(int x)
             {
                 return x+5;
             } 
        }

É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:

InterfaceX o =  Q::anyFunction; 

et cela équivaut à ceci:

InterfaceX o = (x) -> Q.anyFunction(x);

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

Nertan Lucian
la source
1

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 ArrayListavec 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 ::

import java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

class ByVal implements Comparator<MyClass> {
    // no need to create this class when using method reference
    public int compare(MyClass source, MyClass ref) {
        return source.getVal() - ref.getVal();
    }
}

public class FindMaxInCol {
    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, new ByVal());
    }
}

AVEC l'utilisation de ::

import java.util.*;

class MyClass {
    private int val;
    MyClass (int v) { val = v; }
    int getVal() { return val; }
}

public class FindMaxInCol {
    static int compareMyClass(MyClass source, MyClass ref) {
        // This static method is compatible with the compare() method defined by Comparator. 
        // So there's no need to explicitly implement and create an instance of Comparator like the first example.
        return source.getVal() - ref.getVal();
    }

    public static void main(String args[]) {
        ArrayList<MyClass> myClassList = new ArrayList<MyClass>();
        myClassList.add(new MyClass(1));
        myClassList.add(new MyClass(0));
        myClassList.add(new MyClass(3));
        myClassList.add(new MyClass(6));

        MyClass maxValObj = Collections.max(myClassList, FindMaxInCol::compareMyClass);
    }
}
Liutong Chen
la source
-1

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))
ishant kulshreshtha
la source