5
votes

Type de retour d'expression Lambda en Java

J'apprends Lambda en Java et j'essaie de le comprendre. Par exemple, j'ai ce code suivant:

@FunctionalInterface
interface Square 
{ 
    int calculate(int x); 
} 

class Test 
{ 
    public static void main(String args[]) 
    { 
        int a = 5; 

        Square s = (int x) -> x*x; 

        int ans = s.calculate(a); 
        System.out.println(ans); 
    } 
} 

Je ne comprends pas cette déclaration Square s = (int x) -> x * x; Je vois que s est une variable de référence de type Square . Mais je ne comprends pas ce qu'est exactement ce (int x) -> x * x . Est-ce une définition de méthode? Quel est le type de retour de cette méthode? Je pense que cela devrait être int car le type de retour de la méthode Calculate est int . Tout commentaire sera apprécié.


1 commentaires

"qu'est-ce que c'est exactement (int x) -> x * x " C'est une expression lambda , et c'est curieux que vous ayez besoin de demander, puisque le titre de votre question utilise le terme et que vous dites que vous en êtes déjà informé. Dans ce cas, c'est la même chose que x -> x * x , mais avec le type du paramètre lambda explicitement donné.


4 Réponses :


5
votes

Votre expression lambda peut être remplacée par une classe anonyme:

int squared = s.calculate(5);

Donc (int x) -> x * x est juste une implémentation de Calculate qui prend l'argument int et renvoie la valeur int . Par ailleurs, il n'est pas nécessaire de spécifier le type de paramètre. Vous pouvez faire comme:

Square s = x -> x*x;

Vous avez maintenant un objet de type Square et vous pouvez appeler la méthode Calculate qui était défini auparavant dans l'expression lambda:

Square s = new Square() {
    @Override
    public int calculate(int x) {
        return x * x;
    }
};


6 commentaires

Merci pour la réponse, mais est-il possible que s qui est une variable de référence de type Square pointe vers une valeur int?


@gaby Non, car les s doivent pointer vers un objet de type Square . Lorsque vous écrivez (int x) -> x * x , le compilateur créera pour vous un objet de type Square , qui implémente le Calculate méthode utilisant cette expression lambda.


Merci Andreas! Mais comment retourner un objet de type Square? Square est une interface et je sais que vous ne pouvez pas créer d'objet d'interface.


@gaby Vous ne pouvez pas créer une instance d'interface, mais vous pouvez créer une classe anonyme qui implémente cette interface. Voir ici pour plus d'informations stackoverflow.com/questions / 17400664 /…


@Ruslan Ce n'est pas vrai, lambda ne crée pas de classe anonyme, vous pouvez regarder dans le dossier bin pour voir qu'aucune classe anonyme n'est créée lorsque vous utilisez lambda.


@gaby Vous êtes juste. Pour être des expressions lambda précises, utilisez invoquer appel dynamique et ils sont stockés dans le même fichier



1
votes

C'est la syntaxe lambda. C'est du sucre syntaxique pour ...

Square s = new Square ()
   {
   @Override
   public int calculate (int x)
      {
      return x*x;
      }
   }


3 commentaires

Pas vraiment, car une expression lambda ne crée pas de classe anonyme.


@Andreas, eh bien, ce n'est pas APPELÉ une classe anonyme, mais c'est essentiellement la même chose, à part des règles de portée légèrement différentes. Une classe est certainement créée et elle est anonyme.


@DawoodibnKareem Une classe anonyme n'est pas créée par le compilateur pour une expression lambda. Contrairement à une vraie classe anonyme, vous n'obtenez pas de nouveau fichier .class . Le corps de l'expression lambda est compilé dans une méthode cachée (privée, synthétique), par exemple nommé lambda $ 1 , sur la classe contenant le lambda, et l'expression lambda est ensuite compilée en une référence de méthode à cette méthode.



1
votes

Un lambda peut également être considéré comme un moyen rapide de définir (ou redéfinir) une fonction abstraite. (Ils l'appellent sucre syntaxique.) Vous pouvez donc l'écrire comme ceci, aussi:

s = s -> { return s.length()*2 ; } ; 
System.out.println (s.calculate("It!")); // 6

Ce qui se passe, c'est que vous remplissez les blancs de la déclaration de fonction. L'argument est 'x' et le corps de la fonction (aka méthode en Java) est 'return x * x'.

Considérez que vous pourriez faire ceci ensuite, aussi: (Notez l'ajout d'accolades pour prendre en charge un bloc multiligne. Le retour est alors explicitement déclaré. De plus, le type d'entrée peut également être déclaré explicitement - indicateur visuel pour référencer la surcharge.)

int calculate(String x); // note change in argument type -- overloading

Donc, il y a la capacité de réaffecter dynamiquement de nouvelles opérations à une méthode abstraite dans un mécanisme très abrégé.

Considérez que l'interface pourrait également définir quelque chose comme ceci:

s = (int x) -> { return x*x*x ; } ; // brackets allow multi-line operations
System.out.println (s.calculate(2)); // 8 

À ce stade, vous pouvez faire quelque chose comme ceci: (Le type de s est une chaîne .)

Square s; 
s = x -> x*x; 
System.out.println (s.calculate(5)); // 25

En fin de compte, les lambdas fournissent une méthode incroyablement flexible et raccourcie pour définir et redéfinir des méthodes à la volée.


0 commentaires

1
votes

La méthode de calcul dans votre interface Square accepte un int et retourne un int, mais il n'y a pas d'implémentation de la logique comment calculer la valeur de retour car elle n'a pas de corps de méthode {.......} comme les autres méthodes vous le savez peut-être.

Ainsi, l'extrait de code que vous avez ne pointe pas vers un int mais implémente la logique (comment calculer). Il peut être trompeur avec le nom Square mais les expressions suivantes sont valides:

  Square s = (int x) -> x*x; // your example
  Square s1 = (int x) -> x*x*x;    // takes an int x and returns the cube of x
  Square s2 = (int x) -> x+42; // takes an int x and returns x+42
  Square s3 = (int x) -> x%2; // takes an int and returns 0 if x is even 1 otherwise


0 commentaires