web-dev-qa-db-fra.com

Est-ce que l'utilisation des expressions Lambda autant que possible dans Java bonne pratique?

J'ai récemment maîtrisé l'expression Lambda introduite dans Java 8. Je trouve que chaque fois que j'utilise une interface fonctionnelle, j'ai tendance à toujours utiliser une expression Lambda au lieu de créer une classe qui implémente le interface fonctionnelle.

Est-ce considéré comme une bonne pratique? Ou sont leurs situations où l'utilisation d'un Lambda pour une interface fonctionnelle n'est pas appropriée?

52
SteelToe

Il existe un certain nombre de critères qui devraient vous inciter à ne pas utiliser de lambda:

  • Taille Plus un lambda est grand, plus il est difficile de suivre la logique qui l'entoure.
  • Répétition Il est préférable de créer une fonction nommée pour la logique répétée, bien qu'il soit correct de répéter des lambdas très simples qui sont séparés.
  • Naming Si vous pouvez penser à un grand nom sémantique, vous devriez l'utiliser à la place, car cela ajoute beaucoup de clarté à votre code. Je ne parle pas de noms comme priceIsOver100. x -> x.price > 100 est aussi clair que ce nom. Je veux dire des noms comme isEligibleVoter qui remplacent une longue liste de conditions.
  • Imbrication Les lambdas imbriqués sont vraiment, vraiment difficiles à lire.

N'allez pas trop loin. N'oubliez pas que le logiciel peut facilement être modifié. En cas de doute, écrivez-le dans les deux sens et voyez ce qui est plus facile à lire.

117
Karl Bielefeldt

Ça dépend. Chaque fois que vous vous retrouvez à utiliser le même lambda à différents endroits, vous devriez envisager d'implémenter une classe qui implémente l'interface. Mais si vous auriez utilisé une classe interne anonyme sinon je pense qu'un lambda est bien mieux.

14
Tohnmeister

Je soutiens la réponse de Karl Bielefeldt, mais je souhaite apporter un bref ajout.

  • Débogage Certains IDE ont du mal avec la portée à l'intérieur d'un lambda, et ont du mal à afficher les variables membres dans le contexte d'un lambda. Bien que nous espérons que cette situation changera en fin de compte, il peut être ennuyeux de maintenir le code de quelqu'un d'autre lorsqu'il est jonché de lambdas.
14
Jolleyboy

Accès aux variables locales de la portée englobante

La réponse acceptée Réponse de Karl Bielefeldt est correcte. Je peux ajouter une autre distinction:

  • Portée

Le code lambda imbriqué dans une méthode à l'intérieur d'une classe peut accéder à toutes les variables - final trouvées dans cette méthode et cette classe.

La création d'une classe qui implémente l'interface fonctionnelle ne vous donne pas un tel accès direct à l'état du code appelant.

Pour citez le Java (le mien est souligné):

Comme les classes locales et anonymes, les expressions lambda peuvent capturer des variables; ils ont le même accès aux variables locales de la portée englobante . Cependant, contrairement aux classes locales et anonymes, les expressions lambda ne présentent aucun problème de duplication (voir la section Observation pour plus d'informations). Les expressions lambda ont une portée lexicale. Cela signifie qu'ils n'héritent d'aucun nom d'un sur-type ni n'introduisent un nouveau niveau de portée. Les déclarations dans une expression lambda sont interprétées comme elles le sont dans l'environnement englobant.

Ainsi, bien qu'il soit avantageux d'extraire un code long et de le nommer, vous devez le comparer à la simplicité de l'accès direct à l'état de la méthode et de la classe qui les entourent.

Voir:

6
Basil Bourque

Cela pourrait être un choix compliqué, mais à tous les autres excellents points soulevés dans d'autres réponses, j'ajouterais:

Préférer les références de méthode si possible. Comparer:

employees.stream()
         .map(Employee::getName)
         .forEach(System.out::println);

versus

employees.stream()
         .map(employee -> employee.getName())
         .forEach(employeeName -> System.out.println(employeeName));

L'utilisation d'une référence de méthode vous évite d'avoir à nommer les arguments de lambda, qui sont généralement redondants et/ou conduisent à des noms paresseux comme e ou x.

4
Matt McHenry

En s'appuyant sur la réponse de Matt McHenry, il peut y avoir une relation entre lambda et les références de méthode où le lambda peut être réécrit sous la forme d'une série de références de méthode. Par exemple:

employees.stream()
         .forEach(employeeName -> System.out.println(employee.getName()));

contre

employees.stream()
         .map(Employee::getName)
         .forEach(System.out::println);
0
LaFayette