web-dev-qa-db-fra.com

Java8 Lambdas vs classes anonymes

Depuis que Java8 a été récemment publié et que ses toutes nouvelles expressions lambda semblent vraiment cool, je me demandais si cela signifiait la disparition des classes Anonymous que nous connaissions si bien.

J'ai étudié un peu à ce sujet et trouvé quelques exemples intéressants sur la façon dont les expressions Lambda remplaceront systématiquement ces classes, telles que la méthode de tri de Collection, qui permettait auparavant à une instance anonyme de Comparator d'effectuer le tri: 

Collections.sort(personList, new Comparator<Person>(){
  public int compare(Person p1, Person p2){
    return p1.firstName.compareTo(p2.firstName);
  }
});

On peut maintenant utiliser Lambdas: 

Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));

Et semble étonnamment concis. Ma question est donc la suivante: y a-t-il une raison de continuer à utiliser ces classes dans Java8 au lieu de Lambdas?

MODIFIER

Même question, mais dans le sens opposé, quels sont les avantages d'utiliser Lambdas au lieu des classes anonymes, puisque Lambdas ne peut être utilisé qu'avec des interfaces à méthode unique, cette nouvelle fonctionnalité est-elle un raccourci utilisé dans quelques cas ou est-il vraiment utile?

89
Amin Abu-Taleb

Une classe interne anonyme (AIC) peut être utilisée pour créer une sous-classe d'une classe abstraite ou d'une classe concrète. Une AIC peut également fournir une implémentation concrète d'une interface, y compris l'ajout d'un état (champs). Il est possible de faire référence à une instance de AIC en utilisant this dans ses corps de méthodes. Ainsi, d'autres méthodes peuvent être appelées, des modifications peuvent être apportées à son état, etc. Aucune de celles-ci ne s'applique aux lambdas.

J'imagine que la majorité des utilisations des AIC étaient destinées à fournir des implémentations sans fonction de fonctions uniques et qu'elles pouvaient donc être remplacées par des expressions lambda, mais il existe d'autres utilisations pour lesquelles les lambdas ne peuvent pas être utilisées. Les AIC sont là pour rester.

METTRE &AGRAVE; JOUR

Une autre différence entre les AIC et les expressions lambda est que les AIC introduisent un nouveau champ d'application. En d'autres termes, les noms sont résolus à partir des super-classes et des interfaces de l'AIC et peuvent masquer les noms apparaissant dans l'environnement lexicalement englobant. Pour les lambdas, tous les noms sont résolus lexicalement.

86
Stuart Marks

Lambdas, bien que très pratique, ne fonctionnera qu'avec les types SAM. C'est-à-dire des interfaces avec une seule méthode abstraite. Cela échouerait dès que votre interface contient plus d'une méthode abstraite. C'est là que les classes anonymes seront utiles.

Donc, non, nous ne pouvons pas ignorer les classes anonymes. Et juste pour votre information, votre méthode sort() peut être simplifiée en omettant la déclaration de type pour p1 et p2:

Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));

Vous pouvez également utiliser la méthode de référence ici. Soit vous ajoutez une méthode compareByFirstName() dans la classe Person et utilisez:

Collections.sort(personList, Person::compareByFirstName);

ou, ajoutez un getter pour firstName, obtenez directement la Comparator à partir de Comparator.comparing() method:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));
53
Rohit Jain

Performance lambda avec les classes anonymes

Lorsque l'application est lancée, chaque fichier de classe doit être chargé et vérifié.

Les classes anonymes sont traitées par le compilateur en tant que nouveau sous-type pour la classe ou l'interface donnée. Un nouveau fichier de classe est donc généré pour chacune d'elles.

Les Lambda sont différents lors de la génération de bytecode, ils sont plus efficaces et utilisent l’instruction invokedynamic fournie avec JDK7.

Pour Lambdas, cette instruction est utilisée pour retarder la traduction de l'expression lambda en bytecode jusqu'à l'exécution. (l'instruction sera invoquée pour la première fois seulement)

Comme résultat, l'expression Lambda devient une méthode statique (créée à l'exécution) . (Il existe une petite différence avec les cas stateles et statefull, ils sont résolus via les arguments de la méthode générée)

29
Dmitriy Kuzkin

Il y a des différences suivantes: 

1) Syntaxe

Les expressions lambda paraissent bien comparées à la classe anonyme interne (AIC)

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("in run");
        }
    };

    Thread t = new Thread(r);
    t.start(); 
}

//syntax of lambda expression 
public static void main(String[] args) {
    Runnable r = ()->{System.out.println("in run");};
    Thread t = new Thread(r);
    t.start();
}

2) Portée

Une classe interne anonyme est une classe, ce qui signifie qu'elle a la portée d'une variable définie dans la classe interne. 

Considérant que, l'expression lambda n'est pas une portée en soi, mais fait partie de la portée englobante. 

Une règle similaire s'applique aux mots clés super et this lors de l'utilisation d'une classe interne et d'une expression lambda internes anonymes. En cas de classe interne anonyme, ce mot clé fait référence à la portée locale et mot-clé super à la classe super de la classe anonyme. Alors que dans le cas d’une expression lambda, ce mot-clé fait référence à l’objet du type englobant et super fera référence à la super-classe de la classe englobante.

//AIC
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int cnt = 5;    
                System.out.println("in run" + cnt);
            }
        };

        Thread t = new Thread(r);
        t.start();
    }

//Lambda
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = ()->{
            int cnt = 5; //compilation error
            System.out.println("in run"+cnt);};
        Thread t = new Thread(r);
        t.start();
    }

3) Performance

Au moment de l'exécution, les classes internes anonymes requièrent un chargement de classe, une allocation de mémoire, une initialisation d'objet et l'appel d'une méthode non statique, tandis que l'expression lambda est une activité de pure compilation et n'entraîne aucun coût supplémentaire lors de l'exécution. Ainsi, les performances de l'expression lambda sont meilleures que celles des classes internes anonymes. **

** Je réalise que ce point n'est pas tout à fait vrai. Veuillez vous référer à la question suivante pour plus de détails. Performance de classe interne lambda vs anonymous: réduire la charge sur le chargeur de classe?

10
atom217

Lambda en Java 8 a été introduit pour la programmation fonctionnelle. Où vous pouvez éviter le code passe-partout. Je suis tombé sur cet article intéressant sur Lambda.

http://radar.oreilly.com/2014/04/whats-new-in-Java-8-lambdas.html

Il est conseillé d'utiliser les fonctions lambda pour des logiques simples. Si implémenter une logique complexe en utilisant lambdas sera une surcharge pour le débogage du code en cas de problème.

3
Tim
  • la syntaxe lambda ne nécessite pas d'écrire le code évident que Java peut déduire.
  • En utilisant invoke dynamic, lambda ne sont pas reconvertis en classes anonymes pendant la compilation (il n'est pas nécessaire de créer des objets en Java, il suffit de se préoccuper de la signature de la méthode, de se lier à la méthode sans créer d'objet
  • lambda a mis davantage l'accent sur ce que nous voulons faire à la place de ce que nous devons faire avant de pouvoir le faire
0
MagGGG

Permet de comparer la différence entre expression Lambda et classe anonyme.

1. Syntaxe

_ {Classe anonyme:} _

package com.onlyfullstack;
public class LambdaVsAnonymousClass {

 public static void main(String[] args) {
  Runnable runnable = new  Runnable() {
   @Override
   public void run() {
    System.out.println("Anonymous class");
   }
  };

  Thread thread = new Thread(runnable);
  thread.start();
 }
}

_ {Lambda:} _

package com.onlyfullstack;
public class LambdaVsAnonymousClass {

 public static void main(String[] args) {
  Runnable runnable = () -> System.out.println("Lambda Expression");

  Thread thread = new Thread(runnable);
  thread.start();
 }
}

2. Mise en oeuvre

Classe anonyme peut être utilisé pour implémenter n'importe quelle interface avec un nombre quelconque de méthodes abstraites .expression lambda ne fonctionnera qu'avec les types SAM (méthode abstraite unique). C'est-à-dire des interfaces avec une seule méthode abstraite, également appelée interface fonctionnelle. Cela échouerait dès que votre interface contient plus d'une méthode abstraite.

3. Compilation

Classe anonyme: Java crée deux fichiers de classe pour le fichier Java LambdaVsAnonymousClass sous la forme LambdaVsAnonymousClass.class - contient le programme principal LambdaVsAnonymousClass $ 1.class - contient une classe anonyme  enter image description here

Expression Lambda: Avec Expression Lambda, le compilateur créera un seul fichier de classe comme ci-dessous .  Lambda Expression

Ainsi, Java créera le nouveau fichier de classe pour chaque classe anonyme utilisée.

4. Performance

_ {Classes anonymes} _ sont traités par le compilateur comme un nouveau sous-type pour la classe ou l'interface donnée afin qu'un nouveau fichier de classe soit généré pour chaque classe anonyme utilisée. Lorsque l'application est lancée, chaque classe créée pour la classe anonyme est chargée et vérifiée. Ce processus prend beaucoup de temps lorsque vous avez un grand nombre de classes anonymes.

Expressions lambda Au lieu de générer du bytecode direct pour lambda (comme l'approche proposée par le sucre syntaxique de classe anonyme), le compilateur déclare une recette (via des instructions invokeDynamic) et délègue l'approche de construction réelle à l'exécution.

Ainsi, les expressions Lambda sont plus rapides que les classes anonymes car elles ne sont exécutées qu’elles sont appelées.

Pour plus d'informations, veuillez vous référer aux liens ci-dessous: 

https://onlyfullstack.blogspot.com/2019/02/lambda-vs-anonymous-class-in-Java-8.html

https://onlyfullstack.blogspot.com/2019/02/how-lambda-internally-works-in-Java-8.html

0
Saurabh Oza

Les classes anonymes sont là pour rester car lambda convient aux fonctions utilisant des méthodes abstraites simples, mais dans tous les autres cas, les classes internes anonymes sont votre sauveur.

0
spidy