Collections en Java

Maps, Vectors, HashTables et tableaux par exemple

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Une collection en PHP se résume à l'utilisation des arrays. On peut y placer tout type de données possible (mélanger les chaînes de caractères avec les entiers et d'autres tableaux). En Java, le champ de manœuvre est plus grand.

On peut définir une collection comme un objet qui regroupe d'autres objets dans une seule entité. Dans les premières versions du Java étaient accessibles des collections suivantes : - array: il s'agit d'un tableau qui peut être converti en une liste. Cependant, il ne peut pas être agrandi dynamiquement. Il n'accepte qu'un nombre précis d'éléments à son initialisation. L'ajout d'un nouvel élément provoque l'exception ArrayIndexOutOfBoundsException. - Hashtable : il s'agit d'une map ressemblant des paires clé - valeur. Chaque objet pas null peut jouer le rôle de la clé. - Vector : il s'agit d'un tableau qui peut être dynamiquement modifié. Il ne nécessite pas le paramètre de taille à l'initialisation. Contrairement à Hashtable, il n'admet que les clés entiers. La clé d'un élément rajouté dynamiquement doit correspondre à la taille maximale du tableau. Dans le cas contraire, à l'exécution on recevra une ArrayIndexOutOfBoundsException.

Voici un exemple résumant ces trois éléments :

afficher le code

Les version suivantes du Java ont introduit des types de collections plus élaborés. Désormais, on distingue les interfaces de collections suivantes : - Collection : la classe principale dans la hiérarchie des collections. Elle englobe les trois interfaces suivantes (Set, List, Queue). - Set : une collection qui ne peut pas contenir des duplicatas. Il est parent pour l'interface SortedSet - SortedSet : il garde l'ordre de clés ascendant. - List : ressemble à Vector car il peut changer sa taille dynamiquement. Il accepte les duplicatas. - Queue : une collection qui permet de manipuler les éléments en ordre de priorités (selon la régle FIFO - first in, first out [les premiers éléments sont traités d'abord]). - Map : ressemble à Hashtable car il contient des paires clé-valeur. Il est parent pour l'interface SortedMap - SortedMap : une map qui garde l'ordre montant des clés.

Regardons maintenant quelles classes implémentent ces interfaces et à quoi elles peuvent servir dans le cas d'une réelle application :

afficher le code

Différence entre une Map et un Hashtable

Les Maps ressemblent à des Hashtables. Les deux sont pourtant basés sur la rélation clé-valeur. Cependant, il y a quelques différences subtiles entre elles : - les Maps peuvent être parcourous selon : clé, valeur ou clé-valeur et les Hashtables non - Hashtable est synchronisé; il est donc conseillé d'utiliser les Maps dans les applications monoprocessus (mono-threading) - l'implementation d'une Map, HashMap admet les nulls comme valeurs; Hashtable ne le permet pas - Hashtable permet vérifier si une valeur existe (méthode contains()). Une Map rend possible la même opération sur la clé (containsKey()) ou sur une valeur (containsValue())

Différence entre un Set et une Map

Et sur quoi reposent les différences entre un Set et une Map ? Les voici : - les Maps stockent des clés uniques tandis que les Sets les valeurs uniques - les Maps stocket des paires clé-valeur tandis que les Sets contiennent uniquement des instances des objets - les Sets sont ordonnés selon les valeurs, les Maps selon les clés

Types des Maps en Java

HashMap

L'implémentation la plus standarde de l'interface Map. Il s'agit d'une collection des paires clé-valeur. Cette classe accepte les nulls comme clés et valeurs. Comme déjà mentionné, HashMap n'est pas synchronisée en natif. Elle nécessite une synchronisation supplémentaire, par exemple avec l'enveloppeur Collections.synchronizedMap(new HashMap(...)).

TreeMap

Contrairement à HashMap, les valeurs de TreeMap sont ordonnées selon les clés. Elle doit également être synchronisée en plus car elle ne l'est pas par défaut.

LinkedHashMap

Les éléments de cette map sont traités selon l'ordre d'insertion. Comme dans 2 cas précédents, elle n'est pas synchronisé en natif.

IdentityHashMap

Elle ressemble énormément à HashMap. La différence entre elles repose sur la détection si une clé est déjà présente ou pas. IdentityHashMap se base pour cette opération sur l'équation "==" tandis que d'autres maps utilisent la méthode equals(). Autrement dit, la clé sous forme d'un objet String("cle") ne sera pas la même chose que le type primitif "cle" (les deux seront correctement ajoutés dans la map car il s'agit d'une instance du String et d'un type primitif). Elle nécessite également une synchronisation supplémentaire.

WeakHashMap

Sa spécificité concerne les références. Chaque référence fait partie des clés de cette Map. Si une de ces références n'est plus utilisée par l'application (par exemple en devenant un null), le garbage collector de Java va la supprimer de la WeakHashMap pour libérer de l'espace dans la mémoire. Elle est également non synchronisée par défaut.

Elle se base sur l'utilisation de ses références. Si une d'entre elles n'est plus utilisée dans l'application, le garbage collector de Java va la supprimer de la Map et libérer de l'espace dans la mémoire.

Voici les exemples d'implémentation de ces maps :

afficher le code

Plusieurs fois dans l'article on a abordé la problématique de la synchronisation. En effet, pour éviter les problèmes d'accès concurrentiel à une resource, on est obligés de synchroniser les Maps manuellement. Pour ce faire, on peut soit employer la méthode Collections.synchronizedMap(), soit utiliser dans le code ConcurrentHashMap. L'exemple du code ci-dessous illustre en quoi consiste le problème d'accès concurrentiel. Le cas de figure est un bout de code qui gère les équipes participants dans un tournoi. Les équipes sont classées par villes. La condition principale est qu'une ville peut avoir qu'un seule équipe. L'ordre d'inscription est alors important.

afficher le code

Dans ce cas non synchronisé, on s'aperçoit que soit Chelsea est inscrit avant Arsenal, soit l'inverse. Afin de régler ce problème, on peut utiliser ConcurrentHashMap et sa méthode putIfAbsent(). Le code de la classe ClubsList va se présenter ainsi :

afficher le code

Maintenant, en exécutant le code on s'apercevra qu'uniquement une seule équipe est inscrite dans la liste. Et c'est cela que l'application doit faire.

Bartosz KONIECZNY Classes

Une question ? Une remarque ?

*

*

Un conseil Symfony2

Comment importer les routes ?

Parfois on a besoin de partager les routes en fonction de différents environnements (prod, dev / frontend, backend). Symfony2 gère ces cas très facilement. Pour pouvoir partager les routes il suffit tout simplement d'extraire les routes communes et de les importer par la suite. Dans notre exemple on a besoin de partager les routes qui définissent les requêtes AJAX. Pour ce faire, on va les sauvegarder dans le fichier routingAjax.yml, placé dans un bundle qui s'appelle RequestsAjaxBundle/Resource/config/routingAjax.yml. Alors, pour l'utiliser dans le fichier pour des routes de backend, il suffit de l'importer dans l'endroit voulu, comme ici :

# Ajax actions
ajaxRoutes:
    resource: "@RequestsAjaxBundle/Resources/config/routingAjax.yml"