Retours sur java 8 devoxx fr 2016

3 098 vues

Publié le

Java SE 8 est sûrement la version la plus importante et la plus impactante pour les développeurs. Deux ans après sa sortie, ce talk propose des retours sur les bonnes ou moins bonnes utilisations des principales fonctionnalités de Java 8. Une connaissance de ces fonctionnalités est requise.

Publié dans : Logiciels
0 commentaire
5 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
3 098
Sur SlideShare
0
Issues des intégrations
0
Intégrations
1 859
Actions
Partages
0
Téléchargements
32
Commentaires
0
J’aime
5
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Retours sur java 8 devoxx fr 2016

  1. 1. #DevoxxFR Retours sur Jean-Michel Doudoux @jmdoudoux 1#retoursJava8
  2. 2. #DevoxxFR Java 8 2 StampedLock Lambda Stream Date & Time Nashorn Adder Accumulator Base64 Parallel array Interface fonctionnelle Method references Compact ProfilesType Annotations Suppression Perm gen Default Method #retoursJava8
  3. 3. #DevoxxFR Préambule 3 Probablement la mise à jour • la plus importante • la plus impactante Deux ans depuis la release de Java 8 Intéressant de faire une rétrospective Sur ce qui fonctionne bien … ou moins bien Une forte adoption Mais tout le monde ne l’utilise pas encore #retoursJava8
  4. 4. #DevoxxFR Sondage 4 Depuis combien de temps utilisez vous Java 8 ? Plus de 24 mois Moins de 24 mois Moins de 18 mois Moins de 12 mois Moins de 6 mois Pas encore utilisé #retoursJava8
  5. 5. #DevoxxFR 5 Jean-Michel Doudoux http://www.jmdoudoux.fr @jmdoudoux Co-fondateur du , membre du Auteur de 2 didacticiels Diffusés sous licence GNU FDL • Développons en Java (3400 pages) • Développons en Java avec Eclipse CTO chez #retoursJava8
  6. 6. #DevoxxFR Roadmap 6 • Best practices • Optional • Parallel arrays • Date & Time • Lambda • L’API Stream • Impacts sur notre façon de coder #retoursJava8
  7. 7. #DevoxxFR 7 Best practices #retoursJava8
  8. 8. #DevoxxFR Best practices 8 Une méthode ou une technique qui a montré de meilleurs résultats que ceux obtenus avec d'autres moyens Sont contextuelles Sont mouvantes Réévaluations périodiques Sont empiriques et subjectives Issues de l’expérience et son partage #retoursJava8
  9. 9. #DevoxxFR Best practices 9 Différents critères d’appréciation Concernent plusieurs facteurs Maintenabilité, performances, style de code, … Ne sont pas des règles Ne doivent pas devenir des règles à appliquer de manière rigide dans toutes les situations #retoursJava8
  10. 10. #DevoxxFR Disclaimer 10 Une partie de ce talk concerne des best practices Ou peut être assimilé comme tel Ce sont mes opinions exprimées dans ce talk Pour vous permettre : D’obtenir des informations De les évaluer Et (peut être) de les mettre en œuvre #retoursJava8
  11. 11. #DevoxxFR 11 Optional #retoursJava8
  12. 12. #DevoxxFR Définition et limitations 12 Classe qui encapsule : • une valeur • ou l’absence de valeur L'utilisation d'Optional rend le code plus fiable mais cela a un coût (très léger) en performance Classe value-based final N'est pas Serializable #retoursJava8
  13. 13. #DevoxxFR Utilisation 13 Sûrement le sujet le plus controversé Souvent assimilé (à tort) comme certaines fonctionnalités dans d’autres langages Différents cas d'utilisation : • Partout • Dans les API public pour les valeurs de retour et les paramètres • Dans les API public pour les valeurs de retour • Dans des cas spécifiques • Ne jamais utiliser #retoursJava8
  14. 14. #DevoxxFR L'utilisation comme valeur de retour 14 Le cas d'utilisation officiel #retoursJava8 Nécessaire dans certaines circonstances Evite la définition d’une valeur représentant l’absence de valeur Eviter dans les getters de beans Pour limiter les instances de type Optional créées Support plus ou moins facile avec certains frameworks Généralement la durée de vie d'un objet retourné est courte
  15. 15. #DevoxxFR L'utilisation dans les paramètres 15 N'est pas recommandé Pollue la signature de la méthode Plus complexe pour l'appelant public MonMessage(String titre, String contenu, Optional<Attachment> attachment) { // ... } MonMessage m1 = new MonMessage("titre", "contenu", Optional.empty()); Attachment attachment = new Attachment(); MonMessage m2 = new MonMessage("titre", "contenu", Optional.ofNullable(attachment)); #retoursJava8
  16. 16. #DevoxxFR L'utilisation dans les paramètres 16 Préférer l'utilisation de la surcharge de la méthode public MonMessage(String titre, String contenu) { this(titre, contenu, null); } public MonMessage(String titre, String contenu, Attachment attachment) { // ... if (attachment != null) { // ... } #retoursJava8
  17. 17. #DevoxxFR L'utilisation comme variable d’instance 17 Eviter de déclarer des variables d’instances de type Optional Optional n’est pas Serializable Attention au support par certains frameworks #retoursJava8
  18. 18. #DevoxxFR L'utilisation comme variable locale 18 Ne pas déclarer de variable local de type Optional Utiliser null pour indiquer l’absence de valeur Pour un objet Facile à gérer dans le scope d’une méthode #retoursJava8
  19. 19. #DevoxxFR Bonnes pratiques 19 Optional est une classe Ne JAMAIS définir une instance null Toujours utiliser une des fabriques of() ofNullable() empty() #retoursJava8
  20. 20. #DevoxxFR Bonnes pratiques 20 Pour des valeurs primitives : OptionalInt, OptionalLong, OptionalDouble #retoursJava8 Essayer de limiter le caractère optionnel d’une valeur Attention à l'utilisation de la méthode get() Lève une unchecked NoSuchElementException Si aucune valeur n'est encapsulée Utiliser orElse() si possible
  21. 21. #DevoxxFR Bonnes pratiques 21 Eviter d’utiliser Optional typé avec une collection ou un tableau Optional n’apporte aucune plus value Et complexifie le code Préférer une collection ou un tableau vide isEmpty() ou length() pour tester la présence d’éléments #retoursJava8
  22. 22. #DevoxxFR 22 Parallel Arrays #retoursJava8
  23. 23. #DevoxxFR Parallel arrays intro 23 • Méthodes Arrays.parallelXXX() parallelSetAll() : initialisation des éléments parallelSort() : tri des éléments • Exécution des traitements en parallèle Utilise le framework Fork/Join • Apporte un gain de performance plus ou moins important Essentiellement sur des tableaux de grande taille #retoursJava8
  24. 24. #DevoxxFR Utilisation avant Java 8 24 • Initialiser un tableau de 20 millions d'entiers avec des valeurs aléatoires int[] array = new int[20_000_000]; Random rnd = new Random(); for (int i = 0; i < array.length; i++) { array[i] = rnd.nextInt(100); } Benchmark Mode Cnt Score Error Units InitTableauBenchmark.boucleFor avgt 20 271,341 ± 5,606 ms/op #retoursJava8
  25. 25. #DevoxxFR Avec Java 8 : setAll() 25 Code plus compact int[] array = new int[20_000_000]; Random rnd = new Random(); Arrays.setAll(array, i -> rnd.nextInt(100)); Benchmark Mode Cnt Score Error Units InitTableauBenchmark.boucleFor avgt 20 271,341 ± 5,606 ms/op InitTableauBenchmark.setAll avgt 20 271,406 ± 6,411 ms/op Performances similaires #retoursJava8
  26. 26. #DevoxxFR Utilisation de Parallel arrays 26 La méthode parallelSetAll() initialise le tableau de manière parallélisée Beaucoup plus performant puisque parallélisé int[] array = new int[20_000_000]; Random rnd = new Random(); Arrays.parallelSetAll(array, i -> rnd.nextInt(100)); Benchmark Mode Cnt Score Error Units InitTableauBenchmark.setAll avgt 20 271,406 ± 6,411 ms/op InitTableauBenchmark.parallelSetAll avgt 20 2172,501 ± 160,561 ms/op … OU PAS Beaucoup plus lent #retoursJava8
  27. 27. #DevoxxFR Réduction de la contention 27 La classe Random est thread-Safe mais elle induit la contention int[] array = new int[20000000]; ThreadLocalRandom rnd = ThreadLocalRandom.current(); Arrays.parallelSetAll(array, i -> rnd.nextInt(100)); Benchmark Mode Cnt Score Error Units InitTableauBenchmark.setAll avgt 20 271,406 ± 6,411 ms/op InitTableauBenchmark.parallelSetAll avgt 20 2172,501 ± 160,561 ms/op InitTableauBenchmark.parallelSetAllAvecTLR avgt 20 94,822 ± 3,724 ms/op Les performances sont bien meilleures Utilisation de la classe ThreadLocalRandom #retoursJava8
  28. 28. #DevoxxFR Moralité 28 Mais attention aux performances … Sans attentions particulières #retoursJava8 Facile de paralléliser des traitements Simplement en préfixant la méthode par parallel
  29. 29. #DevoxxFR 29 Date & Time #retoursJava8
  30. 30. #DevoxxFR Date & Time intro 30 (Enfin) Une API riche et complète Comble de nombreux manques et lacunes de Date et Calendar Gestion du temps humain et machine Classes non mutables Fluent interface #retoursJava8
  31. 31. #DevoxxFR Bonnes pratiques 31 Déclaration de variables : Temporal localDate = LocalDate.of(2016, 04, 20); LocalDate localDate = LocalDate.of(2016, 04, 20); Bien choisir le type à utiliser selon les données temporelles requises Utiliser cette API plutôt que Date/Calendar ou Joda Time • Ne pas utiliser les interfaces • Utiliser les types #retoursJava8
  32. 32. #DevoxxFR Bonnes pratiques 32 Utilisation des TemporalAdjuster Injecter une instance de type Clock Et utiliser les surcharges qui attendent un type Clock Pour faciliter les tests automatisés Par défaut, renvoie la date/heure système Pour les tests, injecter une instance obtenue par Clock.fixed() #retoursJava8
  33. 33. #DevoxxFR 33 Lambda #retoursJava8
  34. 34. #DevoxxFR Lambda intro 34 Références de méthodes, opérateur :: Fonction anonyme fournit une implémentation pour une interface fonctionnelle (SAM) Syntaxe : (paramètres) -> expression; (paramètres) -> { corps }; Accès aux variables effectivement finale Inférence de types Package java.util.function Function, Predicate, Consumer, Supplier, ... #retoursJava8
  35. 35. #DevoxxFR Bonnes pratiques 35 Utiliser des expressions Lambda plutôt que des classes anonymes internes Privilégier • l'inférence de type des paramètres • l'utilisation des interfaces fonctionnelles fournies dans le JDK Annoter ses interfaces fonctionnelles avec @FunctionalInterface Si l’expression est l’invocation d’une méthode Utiliser les références de méthodes #retoursJava8
  36. 36. #DevoxxFR Bonnes pratiques 36 Garder les expressions Lambda les plus simples possibles Eviter les bloc de code dans les expressions Utiliser les références de méthodes #retoursJava8
  37. 37. #DevoxxFR Les checked exceptions 37 Il est difficile d'intégrer les checked exceptions dans les lambdas #retoursJava8 Les exceptions levées par une expression Doivent être déclarées dans l’interface fonctionnelle La plupart des interfaces fonctionnelles ne déclarent pas d'exceptions Wrapper le code dans un try/catch Qui relève une exception de type RunTime
  38. 38. #DevoxxFR 38 L’API Stream #retoursJava8
  39. 39. #DevoxxFR Stream intro 39 Exécution de traitement sur une séquence d’éléments Obtenus d’une source finie ou infinie Exécution d’un pipeline d’opérations Exécution séquentiel ou parallèle Fluent interface Opérations intermédiaires : lazy, renvoient un Stream Opérations terminales : déclenchent les traitements, ferment le Stream Requiert de penser fonctionnel et pas impératif Ne pas penser boucles et état mutable #retoursJava8
  40. 40. #DevoxxFR Bonnes pratiques 40 Attention à l’ordre des opérations intermédiaires Ex : filter() + sorted() vs sorted() + filter() #retoursJava8 Ne pas abuser des Streams Parfois une boucle est plus lisible Bien adapté pour les Collections, moins pour les Maps Limiter l’utilisation de la méthode forEach()
  41. 41. #DevoxxFR Déboguer un Stream 41 Plutôt difficile majorité des traitements réalisés par l’API Utiliser la méthode peek() peek(System.out::println) ou peek (e –> e) + point d’arrêt Utiliser une référence de méthode + point d’arrêt #retoursJava8
  42. 42. #DevoxxFR Avec des données primitives 42 Utiliser les classes dédiées : DoubleStream, IntStream, LongStream Améliore (grandement) les performances Benchmark Mode Cnt Score Error Units StreamBenchmark.testLongStream avgt 10 233,061 ± 10,962 ms/op StreamBenchmark.testStreamLong avgt 10 4322,430 ± 258,794 ms/op public void testLongStream() { long somme = LongStream .iterate(0, i -> i + 1) .limit(20_000_000) .filter(i -> (i % 2) == 0) .map(i -> i + 1) .sorted() .sum(); } public void testStreamLong() { Long somme = Stream .iterate(0L, i -> i + 1L) .limit(20_000_000) .filter(i -> (i % 2) == 0) .map(i -> i + 1) .sorted() .reduce(0L, Long::sum); } #retoursJava8
  43. 43. #DevoxxFR Les Stream infinis 43 Attention lors de l’utilisation de Stream infinis IntStream.iterate(0, i -> i + 1).forEach(System.out::println); IntStream.iterate(0, i -> i + 1).limit(5).forEach(System.out::println); Il faut introduire une condition d’arrêt #retoursJava8
  44. 44. #DevoxxFR Les Stream infinis 44 Parfois les traitements infinis sont plus subtils List<Double> valeur = Stream .generate(Math::random) .filter(v -> (v > 10) && (v < 20)) .limit(10).collect(Collectors.toList()); List<Double> valeur = Stream .generate(Math::random) .parallel().filter(v -> (v > 10) && (v < 20)) .limit(10).collect(Collectors.toList()); Dans un Stream parallèle, c’est la catastrophe #retoursJava8
  45. 45. #DevoxxFR Les Stream parallèles 45 Facilité de mise en œuvre Ne rime pas forcément avec meilleures performances Utilise le framework Fork/Join Et son pool par défaut Ne pas utiliser d’opérations bloquantes ou trop longues La source de données ne doit pas être modifiée #retoursJava8
  46. 46. #DevoxxFR Les Stream parallèles 46 Attention à certaines opérations intermédiaires Opération stateful : sorted() Opération requérant un ordre : limit() #retoursJava8
  47. 47. #DevoxxFR Les Stream parallèles 47 Attention au Spliterator Certaines sources offrent de mauvaises perf Ex: LinkedList, sources effectuant des I/O, … #retoursJava8 Attention aux Collectors Performance Utilisation d’objets ayant un support de la concurrence Le surcoût de la parallélisation Doit être compensé par le volume de données à traiter
  48. 48. #DevoxxFR Impacts sur notre façon de coder 48#retoursJava8
  49. 49. #DevoxxFR Exemple avec JUnit 5 49 Utilise des fonctionnalités de Java 8 Notamment les Lambda #retoursJava8 Exemple avec JUnit5 (actuellement en version Alpha) Propose de nombreuses fonctionnalités Focus sur celles utilisant Java 8
  50. 50. #DevoxxFR Exemple avec JUnit 5 50 Utilisation des Lambda Dans les assertions assertTrue(() -> "".isEmpty(), "string should be empty"); assertTrue(false, () -> "message évalué de manière lazy"); Dimension dim = new Dimension(800, 600); assertAll("Dimensions non conformes", () -> assertTrue(dim.getWidth() == 800, "width"), () -> assertTrue(dim.getHeight() == 600, "height")); #retoursJava8 Les assertions groupées
  51. 51. #DevoxxFR Exemple avec JUnit 5 51 Pour les assomptions assertThrows(RuntimeException.class, () -> { throw new NullPointerException(); }); assumeTrue("DEV".equals(System.getenv("ENV")), () -> "Arret des tests : execution uniquement sur un poste de DEV"); Throwable exception = expectThrows(RuntimeException.class, () -> { throw new NullPointerException("Ne peux pas etre null"); }); assertEquals("Ne peux pas etre null", exception.getMessage()); #retoursJava8 Pour tester les exceptions levées
  52. 52. #DevoxxFR Exemple avec JUnit 5 52 Définition de tests dans les méthodes par défaut import static org.junit.gen5.api.Assertions.assertEquals; import org.junit.gen5.api.Test; public interface Testable { @Test default void monCasDeTest() { assertEquals(2, 1 + 1); } } public class MonTestable implements Testable { } #retoursJava8
  53. 53. #DevoxxFR Exemple avec JUnit 5 53 Utilisation des annotations répétées Annotations @Tag, @ExtendWith, … import org.junit.gen5.api.Tag; import org.junit.gen5.api.Test; @Tag("tag1") @Tag("tag2") public class MonTest { @Test void monTest() { // … } #retoursJava8
  54. 54. #DevoxxFR Conclusion 54#retoursJava8
  55. 55. #DevoxxFR Conclusion 55 Java 8, c’est aussi beaucoup d’autres fonctionnalités Améliorations de l’API Collection La suppression de la perm gen -> meta space dans Hotspot Nashorn JavaFX StampedLock, Adder, Accumulator, ConcurrentHashMap Java type annotations, annotations répétées Concaténation de chaînes Reflection : accès aux noms des paramètres Base64 … #retoursJava8
  56. 56. #DevoxxFR Conclusion 56 Java 8 changent profondément La manière de coder certaines fonctionnalités #retoursJava8 Attention à la facilité de paralléliser Continuez à approfondir l’utilisation de Java 8 avant l’arrivée de Java 9 Lorsque cela concerne les performances Il faut mesurer, même si cela est (très) difficile avec JMH
  57. 57. #DevoxxFR Merci pour votre attention 57

×