• [^] # Re: Quelques commentaires additionnels

    Posté par . En réponse à la dépêche Java 8 et NetBeans 8 sont disponibles. Évalué à 10.

    Je n'aime pas les lambda. Même si c'est pratique, ça brise le principe DRY

    Il ne faut pas se focaliser sur les lambdas. Java 8 amène en même temps les lambdas, une API stream et les méthodes reference. Ils marchent ensemble.

    Si tu regardes le style Java moderne c'est déjà ce qu'on utilisait sauf que c'était dégueulasse syntaxiquement.

    Maintenant regardons du côté du DRY. Reprenons mon exemple d'hier

     public Collection<String> lambda(Collection<String> c) {
     return c.stream()
     .map((s) -> "foo" + s)
     .collect(Collectors.toList());
     }

    Tu vas dire "foo" + s c'est pas DRY. Ca mériterait d'être défini proprement quelque part pour être réutilisé. Ca tombe bien c'est pour ca que les method references ont été ajoutées en même temps

     static final String addPrefix(String str) {
     return "foo" + str;
     }
     public Collection<String> methodHandle(Collection<String> c) {
     return c.stream()
     .map(Main::addPrefix)
     .collect(Collectors.toList());
     }

    Voilà c'est magique j'ai maintenant un bout de code nommé et isolé qui défini une opération précise. Avant il fallait instancier une fonction statique à la Guava. C'est plus clair et plus performance.

    Maintenant tu vas me dire que c'est cool tant que ton opération à effectué ne dépend que de l'élément lui même. Ca ne marche pas si tu dois paramétrer l'opération avec quelque chose d'autre. Reprenons depuis le début.

     public Collection<String> lambdaWithCustomPrefix(Collection<String> c, String prefix) {
     return c.stream()
     .map(s -> prefix + s)
     .collect(Collectors.toList());
     }

    Retour à la case départ j'ai une lambda que je ne pourrais pas réutiliser et qui n'est pas définie précisément. Dans ce cas la solution method reference ne marche pas car que je peux pas passer mon paramètre supplémentaire. Je peux bidouiller avec le stream API mais c'est pas une bonne idée en soit. Du coup on peut faire quelque chose qui ressemble à ce qu'on faisait avant avec une classe:

     static class PrefixAdder implements Function<String, String> {
     private final String prefix;
     PrefixAdder(String prefix) { this.prefix = prefix; }
     @Override
     public String apply(String str) { return prefix + str; }
     }
     public Collection<String> classWithCustomPrefix(Collection<String> c, String prefix) {
     return c.stream()
     .map(new PrefixAdder(prefix))
     .collect(Collectors.toList());
     }

    Ok ca marche c'est propre à l'appel mais la déclaration est un peu verbeuse. Et ce que je viens d'écrire ca ressemble fortement à une fonction currifiée non ? Java n'est pas fonctionnel pour un sous mais est ce que je pourrais définir une fonction avec un invocation partielle ? Essayons

     Function<String, Function<String, String>> partialPrefixAdder = prefix -> str -> prefix + str;
     public Collection<String> currifyWithCustomPrefix(Collection<String> c, String prefix) {
     return c.stream()
     .map(partialPrefixAdder.apply(prefix))
     .collect(Collectors.toList());
     }

    Oui c'est donc possible. La syntaxe pique les yeux et je suis pas certain que je l'utiliserais en Java mais ca marche.

    Donc oui les lambdas utilisée comme un gros bourrin c'est pas DRY. Maintenant si tu regardes la solution dans son ensemble et que tu branches ton cerveau c'est un très bon outil. lambda pour des trucs qui n'ont pas de sens en dehors de ce traitement précis. Unitée logique nommées pour les opérations réutilisables. L'ajout de Java 8 c'est l'API du stream et les interfaces fonctionnelles. À la limite on aurait presque pu se passer des lambdas.

    Après Java reste Java, ca fait pas grand chose de plus que ce que j'ai décris et t'es loin de Scala par exemple.