[DevoxxFR 2014] 50 nouvelles choses que l’on peut faire avec Java 8

double_xx_texte

Sortie le 18 mars dernier, Java 8 est clairement l’événement de l’année pour la communauté Java. Cette nouvelle version était à l’honneur pour cette édition 2014 avec 2 conférences, 2 university et 1 quickie. Il faut dire qu’elle apporte un grand lot de nouveautés et de bouleversements. L’arrivée des lamdbas expressions, des Streams et des Collectors a introduit des modifications profondes dans le JDK, notamment sur les collections.

Au cours de cette présentation, José Paumard (@JosePaumard) fait le parcours de 50 nouvelles fonctionnalités introduites dans cette dernière version. L’objectif de la session était de présenter les petites améliorations sans s’intéresser aux fonctionnalités phares telles que les lamdbas, les streams, Java FX 2, le moteur javascript Nashborn, etc.

Cette présentation de Java 8 était attendue par de nombreux participants. La salle était comble, un grand nombre de personnes était debout.  Ce qui prouve l’intérêt des développeurs pour cette nouvelle version de Java.  Il faut dire que le speaker, José Paumard est un spécialiste reconnu de la plateforme Java et connaît ce sujet sur le bout des doigts.

Date (JSR 310)

Java 8 arrive avec une nouvelle API pour la gestion du temps, dans le package java.time. Elle est inspirée de la librairie Joda-Time. Stephen Colebourne, créateur de JodaTime, a participé à l’élaboration de celle-ci. Son but est de combler les défauts des vieillissantes API Date (JDK 1.0) et Calendar (JDK 1.1) en introduisant de nouveaux concepts :

  • Instant, représente un point de la ligne de temps (en nanosecondes)
  • Duration, représente une durée entre deux instants. On peut faire de l’arithmétique entre 2 secondes.
Instant start = Instant.now() ;
Instant end = Instant.now() ;
Duration elapsed = Duration.between(start, end) ;
elapsed.plus(2L, TemporalUnit.SECONDS) ;
  • LocalDate, LocalTime et LocalDateTime, représente des dates et heures sans notion de fuseau horaire.
  • Period, représentation « humaine » d’une durée entre LocalDate.
  • ZonedTime, permet la gestion des fuseaux horaires. On a la possibilité de coder des heures localisées, de faire des calculs sur ces heures.
ZonedDateTime.of(
    LocalDate.of(2014, Month.APRIL, 18), // LocalDate
    LocalTime.of (9, 30), //LocalTime
    ZoneId.of("Europe/London")
);
  • TemporalAdjuster, permet de trouver une date à partir d’une autre.
  • DateTimeFormatter, une classe utilitaire pour formater des dates.

Toutes ces classes sont immutables et thread-safe. L’API offre un lien pour convertir les dates de java.time vers les dates des APIs Date/Calendar et inversement.

String

La classe String bénéficie également de la notion de Stream. Les éléments de la  Stream représentent les caractères de la chaîne de caractères.

Une nouvelle façon de concaténer des String fait également son apparition avec l’API StringJoiner. Elle permet de réaliser des concaténations avancées avec la possibilité d’ajouter des chaînes de caractères au début et à la fin de la String.

Exemple d’utilisation de StringJoiner :

String s = new StringJoiner("/", "Devoxx France 2014 débute le " ," à Paris")
    .add("16").add("04").add("2014")
    .toString();
System.out.println(s);
// affiche Devoxx France 2014 débute le 16/04/2014 à Paris.</p>

Une méthode statique « Join » de String permet maintenant de concaténer des chaines de caractères.

I/O

Java 8 NIO est construit sur l’API NIO de Java 7. La plupart des ajouts permettent d’obtenir un java.util.stream.Stream à partir d’un fichier ou d’un InputStream. Ce Stream implémente l’interface AutoCloseable et peut donc utiliser le try-with-resources introduit en java 7 et permettant la gestion automatique des ressources.

L’exemple ci-dessous permet d’afficher chaque ligne d’un fichier :


try (Stream lines = Files.lines(path, UTF_8) {
    lines.onClose(() -> System.out.println("done"))
        .forEach(System.out::println);
}

Il est ainsi possible de streamer les lignes d’un fichier (File.lines), les fichiers d’un répertoire (File.list), mais aussi de ses sous-répertoires (File.walk).

Collection

Les interfaces Collection, List et Iterable profitent d’un grand nombre d’ajouts de nouvelles méthodes. La méthode forEach() permet d’itérer sur chaque élément et prend un consumer. Attention, cette méthode ne fonctionne pas avec les tableaux.  On trouve également des méthodes de modifications removeIf(), replaceAll() et sort().  

Ici un exemple de suppression d’éléments avec un prédicat :

Collection<String> strings = Arrays.asList("one","two","three", "four") ;
Collection<String> list = new ArrayList<>(strings) ;
boolean b = list.removeIf(s -> s.length() > 4) ;
list.forEach(System.out::println) // affiche one, two, three

L’interface Map n’a pas été oubliée avec l’ajout de plusieurs méthodes. Elles ont pour but de faciliter la manipulation des tables de hachage :

  • Map.forEach() itère sur chaque élément
  • Map.replace() remplace une valeur avec sa clé
  • Map.replaceAll() remplace toutes les valeurs en utilisant une Lambda
  • Map.putIfAbsent() ajout une paire clé/valeur si la clé n’existe pas
  • Map.remove() supprime les pairs clés/valeurs
  • Map.merge()  fusionne deux tables de hashage
  • Map.compute() calcul la valeur à partir de la clé et de la valeur existante

Pour finir sur les collections, Comparator a désormais une méthode statique NaturalOrder et possède des méthodes pour réaliser des comparaisons chaînées.

Dans cette exemple, on compare les éléments dans l’ordre suivant : nom, prénom et âge.

Comparator.comparingBy(Person::getLastName)
    .thenComparing(Person::getFirstName)
    .thenComparing(Person:getAge);

Concurrence

Il y a divers ajouts sur différentes parties de l’API Concurrent. Du côté des variables atomiques, deux nouvelles classes font leur apparition : LongAdder et LongAccumulator. Elles offrent de meilleures performances que la classe AtomicLong.

CompletableFuture est une implémentation de l’interface Future permettant de réaliser et de chaîner des tâches asynchrones. StampedLock est une nouvelle implémentation de lock avec lecture optimiste.

Dans l’exemple ci-dessous, on compose des tâches dans le futur pour récupérer une image à partir d’une url.

List<CompletableFuture<Boolean>> result =
CompletableFuture.supplyAsync(
        () -> readWebPage(url)
    )
    .thenCompose(content -> getImages(content))
    .thenApply(image -> writeToDisk(image));

ConcurentHashMap a été complètement réécrite. Cette implémentation est thread-safe et n’utilise pas de lock. Cette nouvelle version représente 6000 lignes de code, 54 classes membres et des nouveaux patterns. Elle reste compatible avec les applications écrites pour les versions antérieures, on remarque aussi que la sérialisation fonctionne entre les implémentations V7 et V8. Comme pour les collections, elle a également son lot de nouvelles méthodes pour la recherche, les itérations et les réductions.

Un exemple d’itérations avec la méthode forEach(), le premier paramètre correspond au taux de parallélisme. Si la taille est supérieure à 10 éléments, la recherche se fait en parallèle.

ConcurrentHashMap<Integer, String> map = ... ;
map.forEach(10,
    (key, value) ->
    System.out.println(String.join(key, "->", value)
);

Pour des besoins plus spécifiques, on peut itérer sur les clés forEachKey() ou sur les valeurs forEachValue().

Conclusion

Cette conférence a permis d’aborder toutes ces petites améliorations et autres « diamants syntaxiques » qui simplifieront la vie des développeurs. On remarque qu’une partie de ces nouveautés profitent de l’introduction des Lambdas et des Streams, notamment les collections. Ces fonctionnalités phares ont un impact très important dans le JDK. L’API Date & Time apporte un renouveau dans la gestion du temps, et comble les défauts des anciennes APIs Date et Calendar.

Je conseille aux développeurs de s’intéresser à cette nouvelle version de Java. Elle apporte une évolution importante du langage, encore plus importante que l’arrivée de Java 5. Des évolutions majeures telles que les Lamdbas ou les Streams ont un impact très fort sur les APIs du JDK et nécessiteront aux développeurs de nouvelles façons de coder les algorithmes.

Pour en savoir plus, les slides de cette présentation sont disponible à cette adresse.

Nombre de vue : 101

AJOUTER UN COMMENTAIRE