La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

La généricité et Java Collection Framework

Présentations similaires


Présentation au sujet: "La généricité et Java Collection Framework"— Transcription de la présentation:

1 La généricité et Java Collection Framework
26/04/2018 La généricité et Java Collection Framework A. Nejeoui

2 Introduction 26/04/2018 JCF est un ensemble d’interfaces et de classes regroupées dans les packages java.util et java.concurrent, cet ensemble offre plusieurs structures de données afin de permettre une organisation, une manipulation et un stockage des objets sous différentes formes. Nous avons besoins de ces structures car chaque application nécessite une organisation bien adaptée de ses objets. Dans une situation vous avez besoins de stocker des objets dupliqués sous un certain ordre, dans une autre situation vous voulez éliminer les objets dupliqués et l’ordre n’est plus important pour vous…etc. ces structures de données sont représentés par un ensemble d’interfaces dans JCF, dans ce chapitre nous allons étudier les interfaces les plus utilisées et nous allons présenter une ou plusieurs implémentation pour chaque interface. Dans ce chapitre nous allons traiter les points suivants : AutoBoxing/UnBoxing Boucle foreach Généricité Interfaces de JCF : Iterator Collection Set, SortedSet et NavigableSet List Map Les implémentations Le 14 Novembre 2008 Qualité du Logiciel

3 AutoBoxing/UnBoxing Rappelez vous que chaque type en Java est considéré soit de type référence ou de type primitif. Les types référence sont les classes, les instances et les tableaux. Comme le montre le tableau suivant il y’a huit types primitif en Java, pour chaque type primitif Java définit une classe ‘enveloppe’ correspondante (wrrapper class) dans le package java.lang. Primitif Wrapper byte Byte short Short int Integer long Long float Float double Double boolean Boolean char Character Le 14 Novembre 2008 Qualité du Logiciel

4 AutoBoxing/UnBoxing La conversion d’un type primitive en un objet de la classe correspondante s’appelle AutoBoxing et la conversion d’un objet en une variable du type primitif correspondant s’appelle unboxing. Java dans sa version 1.5 et supérieur gère automatiquement les conversion AutoBoxing et unboxing si nécessaire. Si par exemple une expression expr de type int apparaît là où un objet de type Integer est attendu, l’AutoBoxing consiste à convertir expr en « new Integer(expr) » et inversement. Exemple : List<Integer> ints = new ArrayList<Integer>(); ints.add(1); int n = ints.get(0); Le 14 Novembre 2008 Qualité du Logiciel

5 Boucle foreach Considérons le code suivant :
List<Integer> ints = Arrays.asList(1,2,3); int s = 0; for (int n : ints) { s += n; } assert s == 6; Cette boucle s’appelle la boucle foreach , ce code est équivalent au code suivant : for (Iterator<Integer> it = ints.iterator(); it.hasNext(); ) { int n = it.next(); //UnBoxing s += n; } La boucle foreach peut être appliquée à tout objet qui implémente l’interface Iterable<E> (définit dans le package java.lang), qui à son tour possède une référence à l’interface Iterator<E> (définit dans le package java.util). Les interfaces Iterable et Iterator définissent les methods iterator(), hasNext() et next(), qui sont utilisé par la boucle foreach. interface Iterable<E> { public Iterator<E> iterator(); } interface Iterator<E> { public boolean hasNext(); public E next(); public void remove(); } Le 14 Novembre 2008 Qualité du Logiciel

6 Généricité Une interface ou une classe peut être déclarée de telle façon qu’elle accepte un ou plusieurs paramètres spécifiés entre < et > Si le paramètre de générique T n’est pas spécifié il est substitué par la classe Object. Le 14 Novembre 2008 Qualité du Logiciel

7 Généricité Exemple : List<String> words = new ArrayList<String>(); words.add("Hello "); words.add("world!"); String s = words.get(0)+words.get(1); Sans la généricité ce code s’écrit : List words = new ArrayList(); String s = ((String)words.get(0))+((String)words.get(1)) assert s.equals("Hello world!"); Les paramètres de généricité sont absents mais il faut faire un transtypage explicite à chaque fois que vous obtenez un élément de la liste. La généricité effectue implicitement les transtypages explicites nécessaires. Remarque : Le bytecode résultant des deux fragments de code précédents est le même. On dit que la généricité en Java est implémentée par Erasure. Le 14 Novembre 2008 Qualité du Logiciel

8 Méthodes Génériques et les Varargs
La méthode statique toList permet de convertir un tableau d’élément de type T en une List<T>. Une méthode déclarée de cette manière s’appelle une méthode générique. Elle est invoquée en utilisant la syntaxe suivante : List<Integer>listInt= GenMethode.<Integer>toList(new Integer[]{1,3,8}); List<String>lisStr= GenMethode.<String>toList(new String[] {"hello", "world“ }); Remarque : on peut ignorer le type lors de l’appel de la méthode si le type peut être déduit automatiquement. List<Integer>listInt= GenMethode.toList(new Integer[]{1,3,8}); Le 14 Novembre 2008 Qualité du Logiciel

9 Méthodes Génériques et les Varargs
La méthode toList précédente accepte un tableau d’élements donc à chaque appel on doit instancier un tableau. Ne serait il pas plus simple si on pourrait passer une liste d’argument dont la taille sera déterminée au moment de l’exécution. La notion de Varargs introduite dans java 1.5 permet de faire ça (voir l’exemple suivant). Le 14 Novembre 2008 Qualité du Logiciel

10 Transtypage de type générique
Si B est un sous type de A alors B<T> est un sous type de A<T> Exemple : List<Number> nums = new ArrayList<Number>(); Si T est différent de S alors il n’ya pas de relation de sou typage entre A<T> et B<S> Le 14 Novembre 2008 Qualité du Logiciel

11 wildcards Examinons la méthode addAll définit dans l’interface collection : Cette méthode accepte comme argument Collection<? extends E> ce qui signifie une Collection<T> pour tout Type T qui hérite de E. Voici un exemple de son utilisation Le 14 Novembre 2008 Qualité du Logiciel

12 wildcards Attention : on ne peut pas stocker des éléments dans un structure E déclaré avec wildcard <? extends T> car elle peut représenter n’import quel E<S> ou S est un sous type de T. voir l’exemple qui suit : Pour pouvoir stocker des éléments sur une structue on doit utiliser le wildcard <? super T> comme suit Le 14 Novembre 2008 Qualité du Logiciel

13 Principe « Get and Put» Le principe Get and Put dicte que si une structure contient un wildcard. On peut seulement obtenir des élément de cette structure s’il s’agit du Wildcard extends ou on peut seulement stocker des valeurs dans cette structure s’il s’agit du wildcard super. Le 14 Novembre 2008 Qualité du Logiciel

14 Redéfinition Covariante
La redéfinition covariante est une technique introduit dans java 1.5 qui permet de redéfinir une méthode avec un type de retour comme étant un sous type de type déclaré dans la super classe. Voir l’exemple qui suit : Le but c’est d’éviter les transtypage unitiles. Le 14 Novembre 2008 Qualité du Logiciel

15 Interfaces de JCF Les principales interfaces de JCF sont présentées dans la figure suivante : Chaque Interface utilise une stratégie avec des avantages et des inconvénients. Il faut donc choisir en fonction des besoins. Le 14 Novembre 2008 Qualité du Logiciel

16 Interface Collection public interface Collection {
// 1) ajout et suppression d'élements boolean add(Object element); // ajout en fin boolean addAll(Collection c); boolean remove(Object element); boolean removeAll(Collection c); boolean retainAll(Collection c); void clear(); // 2) tests d'appartenance boolean contains(Object element); boolean containsAll(Collection c); // 3) divers int size(); // taille de la collection boolean isEmpty(); // vide ? Object[] toArray(); // convertir vers tableau // 4) Iterateurs Iterator iterator(); // parcours de la collection Le 14 Novembre 2008 Qualité du Logiciel

17 Interface Collection Quelques méthodes:
Méthodes add et remove définies de manière suffisamment générale pour avoir un sens aussi bien pour les collections autorisant la duplication des éléments (List) que pour celles ne l’autorisant pas (Set). boolean add(Object o) garantit que la Collection contiendra o après exécution de cette méthode renvoie true si la Collection a été modifiée par l’appel renvoie false si la Collection n’a pas été modifiée boolean remove(Object o) retire une instance d’un élément e tel que : (o==null ? e==null : o.equals(e)) boolean contains(Object o) renvoie true si la Collection contient l’objet o, false sinon ( test fais sur la méthode equals !!) Le 14 Novembre 2008 Qualité du Logiciel

18 Interface Iterator Un Iterator permet le parcours séquentiel des éléments de n’import quelle collection grâce à la méthode iterator() (définit dans Collection) qui retourne un Iterator. L’interface Iterator facilite le parcours des collections ainsi que le retrait des éléments package java.util; public interface Iterator { boolean hasNext(); // encore un élément ? Object next(); // récupérer le suivant void remove(); // enlever le dernier next() } // exemple d'utilisation Collection c = // c : ArrayList, HashSet, etc. Iterator iter = c.iterator(); while(iter.hasNext()) { MonObjet suivant = (MonObjet) iter.next(); // puis manipuler suivant iter.remove();} //ne peut être invoqué qu’une fois par appel de next(). Le 14 Novembre 2008 Qualité du Logiciel

19 Interface List public interface List extends Collection {
// 1) ajout, retrait indexé void add(int index, Object element); void addAll(int index, Collection c); void remove(int index); void removeAll(int index, Collection c); // 2) accès aléatoire Object get(int index); // null si pas trouvé void set(int index, Object element); // 3) divers int indexOf(Object element); // première occurrence int lastIndexOf(Object element); // dernière occurrence List subList(int from, int to); // sous-liste // 4) Itérateurs de liste ListIterator listIterator(); ListIterator listIterator(int index); // depuis index Le 14 Novembre 2008 Qualité du Logiciel

20 Interface ListIterator
L’interface ListIterator est plus riche que Iterator. Il permet de parcourir la collection dans les deux sens (next() et previous()) et d’ajouter ou supprimer des éléments de la collections, cependant cette interface est implémentée seulement par les collection de type List. public interface ListIterator extends Iterator{ void add(Object o); //ajout d’un élément boolean hasNext(); boolean hasPrevious(); Object next(); int nextIndex(); Object previous(); int previousIndex(); void remove(); void set(Object o); //remplacer l’un élément obtenu par next ou previous } Le 14 Novembre 2008 Qualité du Logiciel

21 Interface Set L’interface Set définit un ensemble ne pouvant contenir qu’un exemplaire d’un objet (elle n’accepte pas les éléments dupliqués test fait sur la méthode equals qu’il faut redéfinir pour s’adapter au problème étudié voir diapos suivant). Un Set n'introduit pas de méthodes particulières par rapport à Collection package java.util; public interface Set extends Collection { // rien de plus à signaler boolean add(Object elem); // pas d'ajout si elem est déjà présent dans le Set // (test avec equals()) } Le 14 Novembre 2008 Qualité du Logiciel

22 Le 14 Novembre 2008 Qualité du Logiciel

23 Interface SortedSet Ensemble qui garantit que son Iterator fera un parcours de ses éléments selon un ordre ascendant. lorsque l'on ajoute un élément à un ensemble, l'ensemble doit comparer celui-ci avec les autres éléments déjà présents dans l'ensemble, c'est réalisé par l'envoi du message compareTo(Object) à l'élément. cette méthode est définie dans l'interface java.lang.Comparable. Remarque : Pour être inséré dans une collection triée un objet doit implémenter l'interface java.lang.Comparable Quelques méthodes : E first( ) //premier élément SortedSet<E> headSet(E end) //retourne la liste des éléments inférieur à end E last( ) //dernier élément SortedSet<E> subSet(E start, E end) // retourne la liste des éléments entre start et end SortedSet<E> tailSet(E start)// retourne la liste des éléments suprieur ou égal à start. Le 14 Novembre 2008 Qualité du Logiciel

24 Interface NavigableSet
NavigableSet est une nouvelle interface disponible dans java 6 qui hérite de SortedSet elle permet de manipuler les éléments d’une collection suivant la comparaison de leurs valeurs. Quelques méthodes : E ceiling(E obj) // le plus petit élément elt tel que elt>=obj E floor(E obj) // le plus grand élément elt tel que elt<=obj NavigableSet<E> headSet(E upperBound, boolean incl) // < upperBound ou <= upperBound si inc=true. E higher(E obj) // le plus petit élément elt tel que elt>obj E lower(E obj) // le plus grand élément elt tel que elt<obj NavigableSet<E> subSet(E lowerBound, boolean lowIncl, E upperBound, boolean highIncl) NavigableSet<E> tailSet(E lowerBound, boolean incl) //>lowerBound ou >= lowerBound si incl=true. Le 14 Novembre 2008 Qualité du Logiciel

25 Interface Map Les java.util.Map (associations) mémorisent une collection de couple clé/valeur. si on a une clé, l'association retrouvera la valeur associée à cette clé. Les clés sont uniques, mais la même valeur peut être associée à plusieurs clés Le 14 Novembre 2008 Qualité du Logiciel

26 Interface Map Les objets Map dépendent de deux méthodes particulièrement importantes pour le fonctionnement des collections : hashCode() // calcule le code de hachage des clés equals(Object o) // test d'égalité entre deux clés Ces méthodes sont indisponsables puisqu'elles assure la cohérence de la collection lors de l'utilisation des méthodes get(Object key)// récupère la valeur associée à la clé key put(Object key, Object value)// ajoute un ensemble clé/valeur remove(Object key)//supprime l'ensemble clé/valeur correspondant à la clé key Ainsi si un nouveau couple clé/valeur est ajouté à une collection qui contient déja cette clé la nouvelle valeur remplacera l'ancienne et aucune pair clé/valeur n'est ajouté. Le 14 Novembre 2008 Qualité du Logiciel

27 Interface Map Quelques méthodes : package java.util;
public interface Map { // 1) accès/ajout/retrait/appartenance par clé Object get(Object key); void put(Object key, Object value); void remove(Object key); boolean containsKey(Object key); boolean containsValue(Object value); // 2) accès aux clés et aux valeurs Set keySet(); // l'ensemble des clés Collection values(); // la collection des valeurs // 3) divers int size(); // nombre d'associations int clear(); // tout effacer boolean isEmpty(); // table vide ? Le 14 Novembre 2008 Qualité du Logiciel

28 Les implémentations Dans la première partie de ce chapitre nous avons présenté brièvement les interfaces les plus utilisée dans JCF, et comme nous avons mentionné dans l'introduction, il existe plusieurs implémentations pour chaque interface. Une question plus fréquente est pourquoi le framework ne fournit pas tout simplement la meilleur implémentation pour chaque interface. la réponse nous est fournit par la loi de Murphy qui indique qu'une meilleure implémentation pour un problème donné sera un désastre pour un autre problème Donc vous devez faire une analyse préalable pour déterminer les opérations les plus utilisées dans votre problème et ensuite vous devez choisir l'implémentation qui optimise le plus ces opérations. Les trois principaux types d'opérations que la plupart des collections utilisent sont : L'insertion et la suppression des éléments par position Recherche des éléments par contenu L'itération sur les élément de la collection. Le 14 Novembre 2008 Qualité du Logiciel

29 Les implémentations Le 14 Novembre 2008 Qualité du Logiciel

30 Les implémentations Le 14 Novembre 2008 Qualité du Logiciel

31 Classes de Java et JCF Un nombre de classes sont présentes dans java avant JCF (depuis la version 1.0) Vector Stack Hashtable Properties Elle ont été intégrés à JCF, voir la figure ci-contre. Le 14 Novembre 2008 Qualité du Logiciel

32 La complexité et la notation O
Nous avons évoqué précédemment la notion de «  implémentation meilleure qu’une autre» pour certaines opérations. Cette comparaison concerne l’utilisation des ressource : espace et temps de calcul (CPU time). Généralement une collection utilise une taille mémoire proportionnelle à sa taille. Donc le seul critère de comparaison effectif est le temps de calcul ou encore la complexité de l’algorithme d’une opération donnée. La notation O (grand o) est un moyen pour décrire les performance d'un algorithme d'une manière abstraite sans prendre en considération les détails de l'environnement d'exécution (fréquence du CPU, taille de RAM...) La O notation permet de décrire la performance d'un algorithme en fonction du nombre d'instructions exécutées seulement Temps Nom Exemple d’algorithmes O(1) Constant Insertion dans une table de hachage O(log N) Logarithmique Insertion dans un arbre O(N) linéaire Recherche linéaire O(N2) Quadratique Tri d’une liste Le 14 Novembre 2008 Qualité du Logiciel

33 Implémentations de Set
La classe java.util.HashSet est la classe de base pour mettre en oeuvre des ensembles. La collection HashSet organise des éléments uniques dont l'ordre d'itération est aléatoire. Elle n'accepte qu'un seul élément null. Disposant d'une fonction de hachage les objets HashSet ne garantissent pas l'ordre des éléments durant l'itération car la fonction de hachage disperse les éléments au sein de la collection . Cette classe garantisse un accès constant pour les opération de base comme ajout la suppression et la vérification de présence et l'obtention de taille. – Opérations efficaces: Ajout/Retrait d'élément s.add(e), s.remove(e) Test d'appartenance s.contains(e) Utilisation de l'itérateur de collection Iterator Utilisation principale: pour les clés du HashMap Les objets placés dans un HashSet doivent être « hachables »: Test d'égalité : elem1.equals(elem2) Valeur de hash elem.hashCode() // Contrainte : e1.equals(e2) ==> e1.hashCode() ==e2.hashCode() Le 14 Novembre 2008 Qualité du Logiciel

34 HashSet Quelques méthodes: new HashSet() // new HashSet(int size) //
new HashSet(int size, float lodFactor) // add(Object o) addAll(collection c) remove() isEmpty() iterator() toArray() toArray(E[] e) Le 14 Novembre 2008 Qualité du Logiciel

35 Implémentations de List
Dans ce cours on va traiter 3 implémentations de l’interface List, deux font partie de la collection framework et la troisième fait partie à l’api java 1.0 (ce qu’on appelle « Legacy Class »). ArrayList LinkedList Vector Le 14 Novembre 2008 Qualité du Logiciel

36 ArrayList Cette classe représente un tableau d'objets dont la taille est dynamique. Elle hérite de la classe AbstractList donc elle implémente l'interface List. Le fonctionnement de cette classe est identique à celui de la classe Vector. La différence avec la classe Vector est que cette dernière est multi thread (toutes ces méthodes sont synchronisées). Pour une utilisation dans un thread unique, la synchronisation des méthodes est inutile et coûteuse. Il est alors préférable d'utiliser un objet de la classe ArrayList. Elle définit plusieurs méthodes dont les principales sont : Object get(index) renvoie l'élément du tableau dont la position est précisée int indexOf(Object) renvoie la position de la première occurrence de l'élément fourni en paramètre void removeRange(int,int) supprime tous les éléments du tableau de la première position fourni incluse jusqu'à la dernière position fournie exclue Object set(int, Object) remplace l'élément à la position indiquée par celui fourni en paramètre void trimToSize() ajuste la capacité du tableau sur sa taille actuelle Le 14 Novembre 2008 Qualité du Logiciel

37 ArrayList Chaque objet de type ArrayList gère une capacité qui est le nombre total d'élément qu'il est possible d'insérer avant d'agrandir le tableau. Cette capacité a donc une relation avec le nombre d'éléments contenus dans la collection. Lors d'un ajout dans la collection, cette capacité et le nombre d'éléments de la collection déterminent si le tableau doit être agrandi. Si un nombre important d'élément doit être ajouté, il est possible de forcer l'agrandissement de cette capacité avec la méthode ensureCapacity(). Son usage évite une perte de temps liée au recalcul de la taille de la collection. Un constructeur permet de préciser la capacité initiale. Le temps d’insertion et de suppression d’un élément est proportionnel à la taille de la liste (linéaire) car ces opération nécessitent un recalcul des indexes. Le 14 Novembre 2008 Qualité du Logiciel

38 LinkedList Cette classe hérite de la classe AbstractSequentialList et implémente donc l'interface List. Elle représente une liste doublement chaînée. Cette classe possède un constructeur sans paramètre et un qui demande une collection. Dans ce dernier cas, la liste sera initialisée avec les éléments de la collection fournie en paramètre. Elle gère une collection de façon ordonnée : l'ajout d'un élément peut se faire à la fin de la collection ou après n'importe quel élément. Dans ce cas, l'ajout est lié à la position courante lors d'un parcours. Pour parcourir cette collection : l'interface ListIterator. (li.listIterator()) si un iterator parcours la liste alors qu'un autre fait des mises à jour : CurrentModificationException. Quelques méthodes : void addFirst(Object) / addLast(Object) insère l'objet en début de la liste /fin Object getFirst() /getLast() renvoie le premier élément de la liste / dernier Object removeFirst() / removeLast() supprime le premier élément de la liste et renvoie le premier élément /le dernier Le 14 Novembre 2008 Qualité du Logiciel

39 LinkedList Il n'existe pas de moyen d'obtenir un élément de la liste directement. Pourtant, la méthode contains() permet de savoir si un élément est contenu dans la liste et la méthode get() permet d'obtenir l'élément à la position fournie en paramètre. Il ne faut toutefois pas oublier que ces méthodes parcourent la liste jusqu'à obtention du résultat, ce qui peut être particulièrement gourmand en terme de temps de réponse surtout si la méthode get() est appelée dans une boucle. Pour cette raison, il ne faut surtout pas utiliser la méthode get() pour parcourir la liste. Soulignons que la complexité des opérations effectuées sur une liste chaînée est proportionnelle à l'index sur lequel on effectue ces opérations. Ainsi, une opération sur l'index 0 prendra moins de temps qu'une opération sur l'index 25, ce qui est logique : lorsqu'on effectue une opération sur un élément n d'une liste chaînée, la JVM doit passer par les n-1 précédents de l'élément n. L’avantage principale des liste chaînées est que le temps d’insertion et de suppression d’un élément est constant. Le 14 Novembre 2008 Qualité du Logiciel

40 Vector La classe Vector est la plus utilisée. Elle permet de stocker des objets dans un ensemble de longueur variable, elle support le multithreading. La classe ArrayList est identique à Vector et offre les même fonctionnalité mais elle n’est pas synchronisé (ne supporte pas le multithreading) elle donc plus rapide et plus approprié pour les application non multithreading. Quelques méthodes: add(E e) add(int index, E element) addAll(Collection<? extends E> c) addAll(int index, Collection<? extends E> c) contains(Object o) containsAll(Collection<?> c) elementAt(int index) ensureCapacity(int minCapacity) get(int index) lastIndexOf(Object o, int index) Le 14 Novembre 2008 Qualité du Logiciel

41 Implémentations de Map
La classe java.util.HashMap est la classe de base pour mettre en oeuvre des tables associatives. new HashMap(); Le constructeur par défaut initialise une instance de HashMap avec deux valeurs par défaut, une capacité initiale de 16 et un facteur de charge de 0.75 new HashMap(int size); // spécifier la capcité new HashMap(int size, float loadCharge);// spécifier la capcité et le facteur de chargement. Le facteur de chargement détermine à quel moment l’ensemble doit recalculer la capacité de la HashSet pour accueillir plus d’éléments. – Opérations efficaces: Ajout de couple clé/valeur : tab.put(key,val) Accés par clé: tab.get(key) Retrait par clé: tab.remove(key) Récupérer et itérer sur l'ensemble des clés – tab.keySet() retourne un HashSet – tab.keySet().iterator() pour itérer sur les clés Attention : les clés doivent être « hachées » Le 14 Novembre 2008 Qualité du Logiciel

42 Conclusion Java contient un grand nombre de collections différentes, toutes adaptées à des situations différentes. Le tout est de bien choisir la collection en fonction de ses besoins Avantages : architecture unifiée pour représenter et manipuler les collections réduction de l’effort de programmation amélioration de la qualité et de la performance des programmes facilite l’apprentissage et l’utilisation de nouvelles API. Le 14 Novembre 2008 Qualité du Logiciel

43 Merci pour votre attention
Le 14 Novembre 2008 Qualité du Logiciel


Télécharger ppt "La généricité et Java Collection Framework"

Présentations similaires


Annonces Google