En prévision de l'arrivée de Java 8 dans moins d'un an, Brian Goetz a publié une mise à jour de son document "State of the Lambda" ("Le point sur les Lambda") décrivant les améliorations de l'API Collections. Les expressions lambda étant l'une des fonctionnalités de Java 8 les plus attendues, il était absolument nécessaire de les intégrer parfaitement à l'API Collections. Si vous n'êtes pas encore familiers avec les expressions lambda, vous pouvez vous reporter à un précédent article de la série "State of the Lambda" publié sur InfoQ, décrivant en détail leur syntaxe.
Comme il est inenvisageable de réécrire entièrement l'API Collections, elle sera adaptée pour y intégrer le support des expressions lambda. L'idée est de remplacer les itérations explicites utilisées actuellement (au travers des Itérateurs et des Enumérations notamment) par une itération implicite, par exemple en passant une expression lambda à une méthode forEach() fournie par les collections. Une nouvelle interface, Stream, a été introduite pour modéliser une séquence de valeurs possiblement évaluée de manière paresseuse ("lazy"), ainsi qu'une méthode stream() pour convertir une Collection en Stream.
Les Streams diffèrent des collections en ce qu'ils ne stockent pas leurs valeurs (et peuvent donc être infinis), peuvent être manipulés de manière fonctionnelle, et peuvent être évalués et générés à la demande. Il est ainsi possible de créer une séquence représentant les nombres premiers, chaque élément n'étant calculé que lors de la lecture de l'élément précédent.
L'interface Stream proposera également un certain nombre de méthodes issues de la programmation fonctionnelle, comme forEach(), anyMatch(), map() ou flatMap(). Ces méthodes pourront être implémentées de manière spécifique à chaque collection, ou de manière générique et adaptable à d'autres classes. Le fait que les éléments d'un Stream soient calculés à la demande leur permet d'être consommés, filtrés et convertis même en présence d'une fonction telle que findFirst() : la consommation s'arrête alors dès la découverte d'un élément correspondant au critère, sans besoin de consommer toute de la collection. Voici un exemple tiré du document "State of the Collections" ("Le point sur les Collections") :
Optional<Shape> firstBlue = shapes.stream() .filter(s -> s.getColor() == BLUE) .findFirst();
Le nouveau package java.util.function fournit un ensemble minimal d'interfaces comme Predicate, Function, UnaryOperator et BinaryOperator, l'idée étant d'autoriser les développeurs à intégrer leurs propres types fonctionnels. Il introduit également une nouvelle classe, Optional, qui permet de représenter une valeur potentiellement nulle. Ce wrapper représente soit une instance d'un type particulier, soit une valeur nulle - mais sans les inconvénients d'une référence nulle. Toutefois, tout le monde ne semble pas satisfait de son design, comme en témoigne un échange interminable d'emails le mois dernier. Certains langages, comme Scala ou Haskell, implémentent Optional de manière davantage fonctionnelle, sous la forme d'une monade; mais comme le dit Brian Goetz, "Désolé pour ceux qui aimeraient transformer Java en Scala ou Haskell, mais cela n'arrivera pas." Il avertit également qu'"il est facile pour une minorité bruyante de masquer la voix de la majorité de la communauté". Si certains langages plus spécialisés ou plus fortement typés vont plus loin dans leur support de la programmation fonctionnelle, la plupart des millions de développeur Java ne sont pas familiers de ces concepts, et fournir les outils les mieux adaptés au plus grand nombre est un choix stratégique d'Oracle.
Le support des séquences et des fonctions au sein du langage Java autorise désormais la parallélisation de certaines opération. Une séquence de données peut ainsi être découpée en sous-séquences traitées en parallèle par une architecture adaptée, comme le framework Fork/Join. La version actuelle fournit également un Spliterator, permettant de fragmenter une structure de données importante en unités susceptibles d'être traitées en parallèle. Disposer d'un moyen standard de partitionner une structure de données permet à ladite structure de décider elle-même de son découpage optimal, et au framework Fork/Join de traiter des structures de données de manière totalement générique.
Pour finir, il est probable que l'EL (Expression Language) de Java EE adopte également une forme d'expressions labmda. Il existe déjà des systèmes à la LINQ pour interroger et manipuler les données, mais l'arrivée prochaine des expressions lambda est une bonne occasion pour rapprocher l'EL et le langage Java, et les rendre davantage compatibles et interopérables. Les travaux sur l'EL devraient être terminés vers la fin de l'année, avec une première version attendue pour le premier trimestre 2013.