Le sujet de l’article d’aujourd’hui a pour but de présenter (et/ou rappeler) les différents moyens que l’on peut mettre en oeuvre pour travailler avec une collection en Java.
Pourquoi un tel article me direz vous ? L’ensemble des outils présentés sont connus et reconnus par l’ensemble de la communauté de développeurs.
Eh bien, je suis forcé de constater que ce n’est pas encore tout à fait vrai et que certains les ignorent encore 😉
Les cas d’utilisation que je vais essayer de couvrir sont les suivants :
– Appliquer un traitement à tous les éléments d'une collection,
– Extraire des éléments d'une collection selon certains critères,
– Modifier (ou transformer) tous les éléments d’une collection,
– Gérer des collections typées.
– Construire une List.
Pour traiter ces différents cas, je vais prendre comme référence 3 outils :
-Le JDK (version 6)
– Commons Collections
– Google Guava
Ce sont les 2 principales librairies que j’utilise en général.
Appliquer un traitement à tous les éléments d'une collection
Ce cas est le plus courant. Il consiste à parcourir l’ensemble des éléments de la collection et appliquer un algorithme sur chacun des éléments.
JDK
Avec le JDK, il n’y a pas ‘36 solutions’. Une simple boucle for permettra de réaliser ce cas. Dans la classe Collections, classe utilitaire fournie avec le JDK, pas de méthode permettant de faire cela.
Commons Collections
L’api met à disposition une classe utilitaire nommée CollectionUtils. La méthode
public static void forAllDo(java.util.Collection collection, Closure closure)
permet à partir de l’objet de type Closure d’appliquer un traitement sur chacune des occurrences de l’ensemble.
Google Guava
L’api met à disposition une classe nommée Collection2. La méthode
public static <F,T> Collection<T> transform(Collection<F> fromCollection,
Function<? super F,T> function)
Elle permet d’appliquer la fonction passée en paramètre sur l’ensemble des occurrences de la collection. On remarque la présence des générics pour cette api.
Attention à cette méthode qui applique le traitement de façon lazy.
Extraire des éléments d'une collection selon certains critères
JDK
Une fois n’est pas coutume, mais pour réaliser ce genre d’opération, le JDK reste le parent pauvre dans ce domaine.
En effet, pour collecter un ensemble d’items dans une collection, il n’existe rien que l’on puisse utiliser directement. L’option possible est de faire à nouveau une boucle for et de travailler sur chaque occurrence en implémentant l’algorithme dans le corps de la boucle.
Le principal inconvénient que je peux voir est la difficulté de factorisation du traitement.
Commons Collections
Ici, nous pourrons trouver des outils plus élaborés. Toujours sur la base de la classe CollectionUtils, nous allons avoir recours aux méthodes suivantes :
– public static java.util.Collection select(*)
– public static java.util.Collection selectRejected(*)
– public static void filter(java.util.Collection collection,
Predicate predicate)
Les deux premières méthodes permettent d’effectuer une sélection à partir de critères caractérisés par la classe Prédicate. Cette dernière va permettre de définir des conditions qui rendront éligible ou non, un item de la collection. Chaque item identifié comme éligible sera ajouté à la collection retournée par la méthode.
La première méthode est la réciproque de la deuxième, c’est à dire, que la première va sélectionner les items tandis que l’autre va conserver uniquement ceux qui ne remplissent pas les critères.
La dernière méthode (filter) élimine directement dans la collection passée en paramètre, les items ne répondant pas aux critères.
Google Guava
Nous retrouvons dans cette api, une méthode de sélection que l’on a commenté dans le chapitre précédent :
public static <E> Collection<E> filter(Collection<E> unfiltered,
Predicate<? super E> predicate)
Contrairement à Commons Collections, Guava propose de manipuler les collections dans un contexte sécurisé par l’utilisation des générics.
Modifier (ou transformer) tous les élements d’une collection
On peut avoir le besoin de transformer (changer le type de) l’ensemble des éléments d’une collection. Voyons ce que propose les 3 outils dans ce domaine :
JDK
Pour adresser ce cas, pas de grande nouveauté une nouvelle fois pour le JDK :
– La traditionnelle boucle for
Commons Collections
L’api propose 2 types de méthode :
– public static java.util.Collection collect(*)
– public static void transform(java.util.Collection collection,
Transformer transformer)
Elles se différencient par de petites subtilités, mais elles ont globalement la même fonction.
Google Guava
Pour Guava, une seule méthode, à peu près identique à celle vue ci-dessus :
– public static <F,T> Collection<T> transform(Collection<F> fromCollection,
Function<? super F,T> function)
Nous avons déjà vu cette méthode dans un chapitre précédent.
Gérer des collections typées
Depuis l’arrivée des générics (il y a un moment maintenant 🙂 ), nous sommes en mesure d’écrire du code plus sécurisé. Aujourd’hui, seule la librairie Commons Collections ne permet pas l’utilisation des collections typées. Ce choix a été fait par volonté de garder une compatibilité avec l’ensemble des versions du jdk, notamment sur les versions antérieures à la 5. Néanmoins, Commons Collections propose un mécanisme permettant de gérer ce point.
JDK
Les collections typées sont natives depuis la v5 du JDK. Dans ces conditions, l’utilisation de collection typée ne pose aucun problème.
Au delà du typage statique fourni par les générics, le JDK propose un typage dynamique pour palier à certains cas d’utilisation ou le typage statique ne serait pas suffisant. (http://docs.oracle.com/javase/6/docs/api/index.html?java/util/package-summary.html)
Commons Collections
Comme nous l’avons vu en introduction, cette librairie ne supporte pas les générics. Néanmoins, un mécanisme existe afin de ‘simuler’ le principe.
La méthode suivante permet de créer une collection typée (façon Commons Collections) :
– public static java.util.Collection typedCollection(java.util.Collection collection
java.lang.Class type)
Le principe repose sur le typage dynamique d’une collection. le type des items, qui seront acceptés dans la collection, est défini dynamiquement. Aucune vérification statique ne pourra être effectuée (à la compilation). En revanche, si au runtime une instance d’un type différent est insérée alors une exception sera lancée.
Google Guava
Cette implémentation fait un mix des deux, c’est à dire que l’utilisation des générics est native et que l’on a tout un ensemble d’outils vus en partie ci-dessus permettant de travailler sur les collections.
Construire une List
Ce dernier chapitre va décrire les possibilités offertes pour l’instanciation d’une nouvelle liste.
JDK
Deux possibilités sont offertes :
List<E> myList = new ArrayList<E>();
myList.add(e1);
myList.add(e2);
…
Ou alors, en une seule ligne, avec la classe java.util.Arrays :
List<E> myList = Arrays.asList(e1, e2, e3);
Commons Collections
Je n’ai pas relevé de manière particulière ou plus originale que celle décrite ci dessus.
Google Guava
Chez Google, on a le sens du pratique et du code concis. En effet, la création d’une liste peut se faire via une factory :
public List<E> myList = Lists.newArrayList();
A première vue, rien d’extraordinaire, l’instruction tient sur une ligne, comme pour la version du JDK. En revanche, ce qui est plus appréciable, c’est l’économie d’écriture, dans la partie droite, du type des objets contenus dans la future instance. Ceci grâce à l’inférence de type réalisée sur la partie gauche de l’instruction que le type n’est pas obligatoire.
Une chose plus intéressante encore est la manière d’insérer des valeurs par défaut dans la liste :
public List<E> myList = Lists.newArrayList(e1,e2, e3, e4);
Cette technique est très pratique, notamment dans le cadre de tests unitaires.
Conclusion
En conclusion, en cherchant bien on trouve toujours chaussure à son pied pour travailler avec une collection (que l’on soit sur une version 1.2 du JDK, ou que l’api guava a été acceptée sur le projet).
J’ai un fort penchant pour l’api Guava, qui offre des outils efficaces et élégants à mettre en place.
Je n’ai couvert qu’une infime partie des possibilités offertes par ces outils, l’ensemble des autres types inclus dans les domaines des collections sont aussi couverts par ces outils. N’hésitez pas à mettre le nez dans la javadoc, vous serez surpris de ce que l’on peut y trouver 😉
#java #google #guava #collection #commons