Recherche

Coder's IO

Tag

Collection

Java au quotidien épisode 5 : Collection de multi

 

L’api Guava propose depuis la version 2.0 deux types de collection que l’on ne trouve pas nativement dans le JDK.

Il s’agit des interfaces MultiSet et MultiMap.

Ces deux types apportent des solutions à des problématiques que l’on peut rencontrer assez couramment dans notre quotidien de développeur. 

Multiset

On peut lui ajouter plusieurs éléments (même identiques). Contrairement au Set classique, chaque élément sera référencé dans la collection. 
Pour l’instant rien d’exceptionnel par rapport à une collection classique. La valeur ajoutée de MultiSet est de fournir des fonctionnalités comme :
 – compter le nombre de fois qu’un élément se trouve dans la collection
– extraire un sous-ensemble représentant chaque type stocké dans la collection (distinct),
– possibilité d’ajouter massivement un nombre d'occurrences d’un type,
– etc…

Il existe plusieurs implémentions : 

– HashMultiset
-TreeMultiset
– LinkedHashMultiset
– ConcurrentHashMultiset
– ImmutableMultiset

Multimap

Ce type permet d'indexer sous une clef une collection d’éléments. Contrairement à la Map classique, ou une clef référence une valeur.

Avec les classes du JDK, cette fonctionnalité pourrait être codée de la manière suivante :
Map<K, List<V>>

L’interface Multimap fournit les fonctionnalités suivantes : 

– ajout d’une valeur associée à une clef
– ajout d’une liste de valeurs associée à une clef
– suppression d’une occurrence associée à une clef
– suppression de tous les éléments associés à une clef, et la clef elle même.
– etc…

Nous venons de voir un très bref aperçu des possibilités proposées par ces deux types.

Je vous propose de consulter le pointeur attaché à ce post pour approfondir le sujet.

#java #Guava #Collection   #multiset #multibag

LambdaJ

 

Dans un post précédent, je vous avais parlé des différentes façons de manipuler les collections.
Suite à cet article, +Ronan Michaux  a indiqué un pointeur vers une librairie proposant des fonctionnalités vraiment intéressantes pour la manipulation de collections et plus encore.

Un peu d’histoire..
Ce projet a été initié par +Mario Fusco  en 2009. L’idée originelle du projet est d’augmenter la lisibilité du code et d’éliminer les codes répétitifs que l’on retrouve dans chaque boucle que l’on a à écrire.
Au départ, le créateur du projet a commencé par écrire des méthodes utilitaires et un petit DSL afin de rendre le code plus lisible et plus pratique à utiliser.
Les membres de l’équipe dans laquelle travaille Mario adhèrent immédiatement au projet et commence à l’utiliser quotidiennement.
Face à ce succès, il décide de refactorer ses composants et de les intégrer dans une API indépendante.
La dernière étape de cette mutation a été de choisir le nom de la librairie 🙂

Les fonctionnalités

LambdaJ permet, sur une collection, de : 

– Filtrer les éléments d’une collection, 
– Définir statiquement les propriétés d’un objet,
– Agréger les items d’une collection ou les valeurs des items,
– Joindre des chaînes de caractères,
– Transformer, indexer et trier les items d’une collection,
– Effectuer des regroupements d’items,
– Effectuer du mapping d’objet à objet.

Lorsqu’il s’agit de définir des conditions, typiquement pour la première fonctionnalité citée, LambdaJ se base sur Hamcrest, le framework utilisé principalement dans le cadre de tests unitaires sur la base d’un DSL.

L’ensemble de ces fonctionnalités, comme nous l’évoquions en introduction, vient remplacer les bonnes vieilles boucles itératives (for, while, do).

La syntaxe se base sur un DSL qui permet de rendre le code produit très clair et très expressif. Je vous laisse voir les exemples en suivant le pointeur suivant : http://code.google.com/p/lambdaj/wiki/LambdajFeatures
Comme la syntaxe, les exemples proposés sont très clairs.

Les closures

Le projet propose également une implémentation des Closures. Les closures donnent la possibilité de rendre du code générique pour 95% et de spécialiser les 5% qui restent en respectant le pattern ouvert/fermé.

Les closures proposent un certain nombre de méthodes permettant de gérer facilement le nombre de paramètres que l’on pourra transmettre à la closure.
Aussi, dans le cadre d’une closure définissant un nombre de paramètres fini, il est possible de fixer la valeur de certains de ces paramètres.

Il est possible  de caster des closures dans certaines interfaces afin de pouvoir les manipuler au travers de ces interfaces.
La liste des possibilités concernant les closures n’est pas exhaustive, je vous invite à vous référer à la documentation pour approfondir le sujet.

Étendre la librairie

LambdaJ offre plusieurs interfaces afin de pouvoir introduire les problématiques métier de chacun.

Par exemple :
– personnaliser la conversion d’objet en implémentant l’interface Converter
– enrichir un filtre en étendant la classe LambdaJMatcher

Les performances

Sur le site du projet, on peut trouver un benchmark permettant de mettre en évidence le gain apporté par LambdaJ par rapport à l’utilisation classique des boucles.

En conclusion

Je trouve que par rapport à Guava, la syntaxe proposée ainsi que les fonctionnalités dans LambdaJ sont un cran au-dessus.

Cette librairie est en avance sur son temps, si l’on considère les fonctionnalités proposées dès sa création. En effet, depuis un certain temps maintenant, l’idée d’avoir les lambda expressions natives dans Java est évoquée dans les futurs versions du JDK. Aujourd’hui, nous ne l’’avons pas encore dans le langage ; il faudra attendre la sortie de la version 8 du JDK pour cela.

En attendant, cette librairie permet d’adresser largement les possibilités  de manipulation des collections et des closures. 
Le projet a encore de beaux jours devant lui avant que la version 8 du jdk ne sorte et que celle-ci soit intégrée dans les entreprises.

De mon coté, j’ai ajouté la dépendance sur le projet sur lequel je travaille 🙂

#java #lambdaj #collection #closure #manipulation #data

Travailler avec une collection Java

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

Créez un site Web ou un blog gratuitement sur WordPress.com.

Retour en haut ↑