Puisque Java8 a été récemment publié et que ses toutes nouvelles expressions lambda ont l'air d'être vraiment cool, je me demandais si cela signifiait la disparition des classes Anonymous auxquelles nous étions si habitués.
J'ai fait des recherches un peu à ce sujet et j'ai trouvé quelques exemples intéressants sur la façon dont les expressions Lambda remplaceront systématiquement ces classes, comme la méthode de tri de Collection, qui permettait d'obtenir une instance anonyme de Comparator pour effectuer le tri:
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});
Maintenant, cela peut être fait en utilisant 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 en Java8 au lieu de Lambdas?
ÉDITER
Même question mais dans le sens inverse, 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é n'est-elle qu'un raccourci utilisé uniquement dans quelques cas ou est-ce vraiment utile?
la source
Comparator.comparing(Person::getFirstName)
sigetFirstName()
serait une méthode retournantfirstName
.Réponses:
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'état (champs). Une instance d'une AIC peut être référencée en utilisant
this
dans ses corps de méthode, ainsi d'autres méthodes peuvent être appelées sur elle, son état peut être muté au fil du temps, etc. Aucun de ces éléments ne s'applique aux lambdas.Je suppose que la majorité des utilisations des AIC étaient de fournir des implémentations sans état de fonctions uniques et peuvent donc être remplacées par des expressions lambda, mais il existe d'autres utilisations des AIC pour lesquelles les lambdas ne peuvent pas être utilisées. Les AIC sont là pour rester.
METTRE À JOUR
Une autre différence entre les AIC et les expressions lambda est que les AIC introduisent une nouvelle portée. Autrement dit, les noms sont résolus à partir des superclasses et des interfaces de l'AIC et peuvent masquer les noms qui se produisent dans l'environnement lexical englobant. Pour les lambdas, tous les noms sont résolus lexicalement.
la source
A$1.class
mais pas Lambda. Puis-je ajouter ceci dans Différence?LambdaClass$$Lambda$1/1078694789
. Cependant, cette classe est générée à la volée par la métafactory lambda, pas parjavac
, il n'y a donc pas de.class
fichier correspondant . Encore une fois, cependant, il s'agit d'un problème de mise en œuvre.Lambdas, bien qu'une fonctionnalité intéressante, ne fonctionnera qu'avec les types SAM. Autrement dit, s'interface avec une seule méthode abstraite. Il échouerait dès que votre interface contiendrait plus d'une méthode abstraite. C'est là que les classes anonymes seront utiles.
Donc, non, nous ne pouvons pas simplement ignorer les classes anonymes. Et juste pour info, votre
sort()
méthode peut être plus simplifiée, en ignorant la déclaration de type pourp1
etp2
:Vous pouvez également utiliser la référence de méthode ici. Soit vous ajoutez une
compareByFirstName()
méthode dans laPerson
classe, et utilisez:ou, ajoutez un getter pour
firstName
, obtenez directement la méthodeComparator
fromComparator.comparing()
:la source
new @MyTypeAnnotation SomeInterface(){};
. Cela n'est pas possible pour les expressions lambda. Pour plus de détails, consultez ma question ici: Annoter l'interface fonctionnelle d'une expression Lambda .Performances 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 comme un nouveau sous-type pour la classe ou l'interface donnée, de sorte qu'un nouveau fichier de classe sera généré pour chacune.
Les lambdas sont différents lors de la génération de bytecode, ils sont plus efficaces, ils utilisent l'instruction invokedynamic fournie avec JDK7.
Pour Lambdas, cette instruction est utilisée pour retarder la traduction de l'expression lambda dans le bytecode jusqu'à l'exécution. (l'instruction ne sera invoquée que pour la première fois)
En conséquence, l'expression Lambda deviendra une méthode statique (créée au moment de l'exécution). (Il y a une petite différence avec les statels et les cas avec état, ils sont résolus via des arguments de méthode générés)
la source
invokedynamic
ce qui est généralement plus lent que celuiinvokespecial
utilisé pour créer de nouvelles instances de classes anonymes. Donc, dans ce sens, les lambdas sont également plus lentes (cependant, la JVM peut optimiser lesinvokedynamic
appels la plupart du temps).invokedynamic
avec la génération de classes ad hoc, la génération est extrêmement rapide par rapport aux classes anonymes compilées.Il existe les différences suivantes:
1) Syntaxe
Les expressions Lambda semblent soignées par rapport à la classe interne anonyme (AIC)
2) Portée
Une classe interne anonyme est une classe, ce qui signifie qu'elle a une portée pour la variable définie à l'intérieur de la classe interne.
Alors 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 pour super et ce mot clé lors de l'utilisation à l'intérieur d'une classe interne anonyme et d'une expression lambda. Dans le cas d'une classe interne anonyme, ce mot clé fait référence à la portée locale et le mot clé super fait référence à la super classe 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.
3) Performance
Au moment de l'exécution, les classes internes anonymes nécessitent le chargement de classe, l'allocation de mémoire, l'initialisation d'objet et l'appel d'une méthode non statique, tandis que l'expression lambda est une activité de compilation pure et n'entraîne pas de coût supplémentaire pendant l'exécution. Les performances de l'expression lambda sont donc meilleures que celles des classes internes anonymes. **
** Je me rends compte que ce point n'est pas entièrement vrai. Veuillez vous référer à la question suivante pour plus de détails. Lambda vs performances de classe interne anonyme: réduire la charge sur le ClassLoader?
la source
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 les lambda.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
Il est conseillé d'utiliser les fonctions lambda pour les logiques simples. Si l'implémentation d'une logique complexe à l'aide de lambdas sera une surcharge dans le débogage du code en cas de problème.
la source
Les classes anonymes sont là pour rester car lambda est bon pour les fonctions avec des méthodes abstraites uniques mais pour tous les autres cas, les classes internes anonymes sont votre sauveur.
la source
invoke dynamic
, lambda ne sont pas reconvertis en classes anonymes pendant la compilation (Java n'a pas à passer par la création d'objets, se soucie juste de la signature de la méthode, peut se lier à la méthode sans créer d'objetla source