50 nouvelles choses que l'on peut faire avec Java 8

Retour sur la conférence Devoxx 2014

| Julien Sadaoui (Soat) | Soat |

Cet article s'intéresse à la session « 50 nouvelles choses que l'on peut faire avec Java 8 » présentée par José Paumard lors de la conférence Devoxx France 2014.

Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum Commentez . ♪

- Titre : 50 nouvelles choses que l'on peut faire avec Java 8

- Auteurs : Julien Sadaoui (Soat), Soat

- Parution : 15 septembre 2014

- Licence : Copyright ® 2014 Soat. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Date (JSR 310)

- III. String

- IV. I/O

- V. Collection

- VI. Concurrence

- VII. Conclusion

- VIII. Remerciements

I - Introduction

Sorti 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 deux conférences, deux university et un quickie. Il faut dire qu'elle apporte un grand lot de nouveautés et de bouleversements. L'arrivée des lambda 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 lambda, 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 plate-forme Java et connaît ce sujet sur le bout des doigts.

II - 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 deux 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 API Date/Calendar et inversement.

III - 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.

Une méthode statique « join » de String permet maintenant de concaténer des chaînes de caractères.

IV - 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).

V - 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, four

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 expression ;

- Map.putIfAbsent() ajout d'une paire clé/valeur si la clé n'existe pas ;

- Map.remove() supprime les paires clés/valeurs ;

- Map.merge() fusionne deux tables de hashage ;

- Map.compute() calcule 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 cet 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);

VI - 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().

VII - 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 Lambda 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 API 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 Lamdba ou les Streams ont un impact très fort sur les API du JDK et nécessiteront pour les développeurs de nouvelles façons de coder les algorithmes.

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

VIII - Remerciements

Cet article a été publié avec l'aimable autorisation de la société Soat.

Nous tenons à remercier Jacques THÉRY et Malick SECK pour leur relecture orthographique attentive de cet article et Régis Pouiller pour la mise au gabarit.