• Aucun résultat trouvé

Algorithmique avancée

N/A
N/A
Protected

Academic year: 2022

Partager "Algorithmique avancée"

Copied!
24
0
0

Texte intégral

(1)

Algorithmique avancée

les collections Java

(2)

Plan

Les 4 types principaux.

Implémentations fournies par l'API.

Parcours d’une collection.

« Magouilles » Java

(3)

Les 4 types principaux

A partir de la v5 java : refonte complète des classes proposant des tableaux/listes.

résultat : ensemble « cohérent » de classe appelé Collections.

cohérence :

méthodes communes, par ex. size(),

règles de nommage, par ex, get()

MAIS ... pas si cohérent que ça à cause des différences fonctionnelles entre les types proposés.

(4)

Les 4 types principaux

4 types :

Set : ensemble d'objets non indicé, non ordonné, sans doublon.

List : ensemble d'objets indicé (donc ordonné au sens des indices), potentiellement avec doublon.

Map : ensemble associatif, un objet clé référence un objet valeur. Pas de clé en doublon mais plusieurs clés peuvent référencer le même objet valeur.

Queue : FIFO (file) / LIFO (pile).

(5)

Les 4 types principaux

Dans l'API, Set, List, Map, Queue = classes interface.

ne définissent que les prototypes des méthodes manipulant ces types de collection.

=> pas instanciable.

l'API propose plusieurs implémentations de chaque interface.

En pratique : une seule implémentation vraiment utile par interface =

HashSet, ArrayList, HashMap, ArrayDeque.

(6)

Les implémentations

Ces 4 classes proposent les traitements classiques :

accès lecture/modification.

insertion/suppression.

taille, vidage, …

Si l'application a un schéma d'accès particulier (beaucoup insertion/suppression, insertion ordonnée, …) : d'autres implémentations peuvent être plus performantes.

(7)

Les implémentations : généricité

Avant la v5 de Java : pas de généricité => on crée des listes d'Object.

La classe Object étant à la base de toutes les autres, on peut créer une liste où l'on met n'importe quel type

d'instance dedans.

pour récupérer & manipuler l'objet : transtypage et possibilité d'erreur à l'exécution.

Date da = new Date();

Integer i = new Integer(56);

Vector v = new Vector();

v.add(d);

v.add(i);

Object o = v.elementAt(0);

Date d2 = (Date)o; // OK

Integer j = (Integer)o; // Erreur transtypage A L'EXECUTION

(8)

Les implémentations : généricité

A partir de la v5 de Java : possibilité d'écrire des classes générique => les types de certains attributs sont

déterminés par le programmeur dans son code.

Les classes de collections utilisent la généricité :

un seul type d'objet dans une collection.

pas d'erreur de transtypage à l'exécution

ArrayList<String> list = null; // déclaration ...

list = new ArrayList<>(); // instanciation list.add("Salut");

list.add(new Date()); // erreur COMPILATION String s = list.get(0);

Integer i = list.get(0); // erreur COMPILATION

(9)

Les implémentations : généricité

Remarques :

Souvent déclaration/définition en utilisant le polymorphisme.

Type générique = forcément nom de classe.

Pas nécessaire de remettre le type générique lors de l’instanciation.

List<String> list = null; // déclaration avec la classe interface

list = new ArrayList<String>(); // instanciation de l’implémentation de l'interface

Set<int> set = new HashSet<int>(); // erreur compilation car type = int Set<Integer> set = new HashSet<Integer>(); // OK

Set<Integer> set = new HashSet<>(); // OK, compilo connait déjà le type

(10)

Les implémentations : méthodes communes

Quelle que soit la classe, il y a les méthodes :

int size() : pour obtenir le nombre d'éléments stockés dans la collection.

boolean isEmpty() : pour savoir si la collection est vide.

void clear() : pour vider la collection.

(11)

Les implémentations : HashSet

HashSet = ensemble non indicé sans doublon.

boolean add(E e) : ajoute e dans la collection, renvoie false si e existe déjà, true sinon.

Rq : si E n'est pas le nom de classe utilisé lors de la déclaration => erreur COMPILATION

boolean remove(Object o): supprime o s'il existe, sinon renvoie false.

Rq : si o n'est pas de la classe utilisée lors de la déclaration, pas d'erreur mais renvoie false.

boolean contains(Object o) : renvoie true si o existe dans la collection, false sinon.

(12)

Les implémentations : HashSet

Exemple d’utilisation HashSet :

public class A { ... }

public class B extends A { ... } public class Prog {

...

Set<A> set = new HashSet<>(); // instanciation A a = new A(...);

B b = new B(...);

Date d = new Date();

set.add(a); // OK

set.add(b); // OK car B sous-classe de A : polymorphisme set.add(d); // erreur compilation

boolean rep;

rep = set.remove(a); // OK, renvoie true rep = set.contains(d); // OK, renvoie false rep = set.remove(d); // OK, renvoie false ...

(13)

Les implémentations : ArrayList

ArrayList = ensemble indicé

boolean add(E e) : insère e en fin de liste

void add(int idx, E e) : insère e en idx. Si idx non valide, lève une exception (idem pour les autres méthodes avec idx)

E remove(int idx): supprime et renvoie l'élément en idx

E get(int idx) : renvoie l'élément en idx.

int indexOf(Object o) : renvoie l'indice de o s'il existe (-1 sinon).

(14)

Les implémentations : ArrayList

Exemple d’utilisation ArrayList :

List<A> list = new ArrayList<>();

A a1 = new A(...);

A a2 = new A(...);

Date d = new Date();

list.add(a1); // OK list.add(a2); // OK

list.add(d); // erreur compilation -> mauvais type

list.add(15,a1); // erreur exécution : index en dehors de la liste A aa = null;

aa = list.get(0); // OK et aa référence le même objet que a1 aa = list.remove(1); // OK et aa référence le même objet que a2 int pos = list.indexOf(a1); // OK et renvoie 0

pos = list.indexOf(d); // OK et renvoie -1

(15)

Les implémentations : HashMap

HashMap = tableau associatif clé/valeur

V put(K k, V v) : associe la clé k à la valeur v. Si k était déjà associée à une valeur, renvoie celle-ci, sinon null.

V get(Object k) : renvoie la valeur associé à l'objet k, s'il existe en tant que clé, sinon renvoie null.

V remove(Object k): supprime k et la valeur

associé, si k existe en tant que clé, sinon renvoie null.

boolean containsKey(Object k)

boolean containsValue(Object v)

(16)

Les implémentations : HashMap

Exemple d’utilisation HashMap :

Map<String,A> map1 = new HashMap<>();

Map<A,Integer> map2 = new HashMap<>();

A a1 = new A(...);

A a2 = new A(...);

Date d = new Date();

map1.put("toto",a1); // OK, renvoie null

map1.put("toto",a2); // OK, renvoie valeur précédente (i.e. a1)

map1.put(a1,"tutu"); // erreur compilation : mauvais types cle/valeur map2.put(a1, new Integer(10); // OK, renvoie val. prec. (i.e. tutu) map2.put(d, new Integer(5)); // erreur compilation : mauvais type clé map2.containsKey(d); // OK, renvoie false : clé inexistante

maps.containsKey(a1); // OK, renvoie true

map2.remove(d); // OK mais ne fait rien : clé inexistante.

map1.remove("toto"); // OK, renvoie a2

map1.remove(a1); // OK, renvoie l'objet Integer.

(17)

Les implémentations : ArrayDeque

ArrayDeque = FIFO ou LIFO

Rq : pas de différence d'instanciation, seulement les méthodes utilisées.

mode file (FIFO) :

boolean offer(E e) : ajoute e en fin de file.

E poll() : renvoie l'objet en tête de file.

mode pile (LIFO) :

void push(E e): ajoute au sommet de la pile.

E pop(): renvoie l'objet au sommet de la pile.

Rq : offer() et push() ont le même effet.

(18)

Les implémentations : ArrayDeque

Exemple d’utilisation ArrayDeque :

Queue<Double> q = new ArrayDeque<>();

// FIFO access q.offer(1);

q.offer(2);

int val = q.poll(); // renvoie 1 // LIFO access

q.push(3);

val = q.pop(); // renvoie 3 val = q.pop(); // renvoie 2

(19)

Parcours d’une collection

deux procédés :

boucle for :

syntaxe spéciale.

uniquement si aucune insertion/suppression dans la collection.

objet Iterator :

création d’un objet servant d’itérateur,

possibilité d’insertion/suppression,

selon type, retour en arrière possible.

(20)

Parcours d’une collection : for

Exemple avec for :

Set<String> set = new HashSet<>();

List<Date> list = new ArrayList<>();

Map<Integer,String> map = new HashMap<>();

for(String s : set) {

... // faire qqchose avec s }

for(Date d : list) {

... // faire qqchose avec d }

for(Map.Entry<Integer, String> e : map.entrySet() ) { Integer key = e.getKey();

String value = e.getValue();

... // faire qqchose avec key et value }

(21)

Parcours d’une collection : itérateur

Exemple avec itérateur :

Set<String> set = new HashSet<>();

List<Date> list = new ArrayList<>();

Map<Integer,String> map = new HashMap<>();

Iterator<String> is = set.iterator();

while (is.hasNext()) { String s = is.next();

...

if (...) is.remove();

...

}

ListIterator il = list.listIterator();

while (il.hasNext()) { Date d = il.next();

...

// possibilités : il.previous(), il.add(E e), il.remove(), ...

}

(22)

Parcours d’une collection : itérateur

Exemple avec itérateur (suite):

Iterator<Integer> im = map.keySet().iterator();

while(im.hasNext()) {

Integer key = im.next();

String val = map.get(key);

...

}

(23)

« Magouilles » Java

généricité limitée aux objets = gênant.

contournement : (dés)encapsulation automatique des

types primaires (char, int, double, …) dans des instances des classes équivalentes (Char, Integer, Double, …).

magouille du compilateur, car brise les principes

fondamentaux de vérification du typage des variables.

Danger : bizarreries avec les tests du type == et !=.

Map<Integer,Double> map = HashMap<>();

map.put(5, 1.234); // OK : encapsulation automatique de int et double double val = map.get(5); // val contient 1.234 : désencapsulation

// RQ : principe applicable partout dans le code, e.g Double d = 6.666; // OK : encapsulation automatique

if (d == 6.666) { ... } ; // OK aussi grâce à désencapsulation

(24)

« Magouilles » Java

Danger : bizarreries avec les tests == et !=

Integer i1 = 10; // encapsulation Integer i2 = 10; // encapsulation

Integer i3 = new Integer(10); // instanciation classique if (i1 == i2) S.o.p("egal 1"); // affiche egal 1

if (i1 == i3) S.o.p("egal 2"); // n’affiche rien ! Integer i4 = 1000; // encapsulation

Integer i5 = 1000; // encapsulation

if (i4 == i5) S.o.p("egal 3"); // n’affiche rien, argh !!!!!!!

Conclusion : ne pas faire de tests entre objets qui ont pour origine une donnée encapsulée.

Références

Documents relatifs

de même que dans les sociétés d'ingénierie, les bureaux d'études et, bien sûr, chez les développeurs de logiciels de calcul scientifique et dans la recherche en informatique.

• Diplôme d'ingénieur de l'Ecole supérieure de chimie physique électronique de Lyon spécialité chimie génie des procédés. • Diplôme d'ingénieur de l'Ecole supérieure

Sciences, technologies, organisations mention ingénierie systèmes électronique électrotechnique automatique productique et réseaux spécialité génie électrique

• Diplôme d'ingénieur de l'Ecole nationale supérieure des sciences appliquées et de technologie de Lannion de l'Université Rennes I spécialité électronique et

• Master pro Droit et science politique mention environnement risque spécialité droit et gestion de l'environnement. • Master pro Droit et science politique mention

• Diplôme d'ingénieur de l'année de spécialisation mécanique des fluides et hydraulique de l'Institut national polytechnique de Toulouse. • Diplôme d'ingénieur de

• Quelques exemples de masters professionnels : physique-qualité-radioprotection mention radioprotection à l'INSTN ; sciences, technologies, santé mention ingénierie,

• Diplôme d'ingénieur de l'Institut supérieur des techniques avancées de l'Université de Saint-Étienne spécialité optique (optique et vision industrielles) en partenariat