Conteneurs et exceptions§

Conteneurs§

Résumé du package§

Le package java.util regroupe des classes relatives à la gestion du temps, à la gestion des événements, ainsi qu'aux conteneurs (collections et tableaux associatifs).

Un conteneur est un ensemble générique d’objets (jeu de cartes, répertoire de fichiers, sac de perles, annuaire téléphonique, dictionnaire, etc.).

L'efficacité du codage particulier d'une collection dépend de ses caractéristiques (ordre, doublons, etc.) et des opérations envisagées (parcours, ajout, suppression, concaténation, etc.).

Conteneurs§

Le package java.util propose les conteneurs suivants:

(Cette liste n'est pas exhaustive).

On utilise le plus souvent ArrayList, HashSet, HashMap.

Ex.1. Conteneurs (10 min)§

L'interface Collection§

Les interfaces List et Set dérivent de Collection, dérivant elle-même de Iterable.

Elle exige la présence, entre autres, des méthodes suivantes:

La méthode iterator(), requise par Iterable, renvoie un objet issu d'une classe implémentant l'interface Iterator, avec lequel on peut parcourir la collection.

L'interface Iterator§

Un objet de type Iterator offre un moyen de parcourir la collection à laquelle il réfère:

Collection<Integer> c = new ArrayList<Integer>();
...
for (Iterator<Integer> it = c.iterator(); it.hasNext(); ) {
    System.out.println( it.next() );
}

Depuis java 5, vous pouvez utiliser ce raccourci:

for (Integer i: c) {
    System.out.println( i );
}

Généricité§

Comme vous le voyez, depuis java 5, les classes et les interfaces peuvent être paramétrées par un type.

public class StackByLinkedList<E> {
    ...
}

Lors de la déclaration, le type formel est remplacé par le type effectif (non primitif).

StackByLinkedList<Integer> s = new StackByLinkedList<Integer>();

Le fonctionnement est le même que celui du passage de paramètres pour une méthode.

L'interface Map§

L'interface Map décrit des objets qui mettent en correspondance des clés et des valeurs (à une clé étant associé au plus une valeur).

En plus de la méthode get() renvoyant la valeur associée à une clé donnée, elle offre trois vues de type Collection:

L'interface Map.Entry§

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

L'interface Map.Entry représente une paire clé-valeur: getKey() retourne la clé, tandis que getValue() retourne la valeur.

Iterator<Map.Entry<Integer,String> > it;
for (it = annuaire.entrySet().iterator(); it.hasNext(); ) {
    Map.Entry<Integer,String> e = it.next();
    System.out.println(e.getKey() + ": " + e.getValue());
}
for (Map.Entry<Integer,String> e: annuaire.entrySet()) {
    System.out.println(e.getKey() + ": " + e.getValue());
}

Ex.2. Etudiants (15 min)§

Pour aller plus loin (15 min)§

Ce qu'il faut retenir§

Exceptions§

Erreurs et exceptions§

Les exceptions désignent les situations où l'exécution peut se poursuivre, généralement de façon différente. Elles sont matérialisées en Java par des instances de classes dérivant de java.lang.Exception, elle-même dérivant de java.lang.Throwable.

java.lang.Object
java.lang.Throwable
java.lang.Exception

N'hésitez pas à lire les tutoriaux qui traitent le sujet.

Le développeur§

Le développeur d'une classe peut lever une exception au moment opportun avec le mot-clé throw et peut indiquer aux clients que la méthode concernée est susceptible de lever une exception avec le mot-clé throws.

     public int pop() throws RuntimeException {
         if ( myNode == null )
             throw new RuntimeException();
         else
             myNode = myNode.next();
     }

Le client qui traite les exceptions§

Le bloc d'instructions principal est mis dans un bloc try, tandis que la gestion des exceptions est répartie, selon la nature de l'exception, dans des blocs catch successifs.

try {
    /* code */
} catch(ExceptionDeTypeA e) {
    /* gestion des exceptions de type A */
} catch(ExceptionDeTypeB e) {
    /* gestion des exceptions de type B */
} finally {
    /* tout fermer et nettoyer */
}

Le bloc optionnel finally s'exécute toujours.

Propager une exception§

private static void oneMove(Stack src, Stack dest)
  throws RuntimeException {
    try {
        dest.push( src.top() );
        src.pop();
    } catch (RuntimeException e) {
        throw new RuntimeException();
    }
}

Plutôt que d'attraper et lever la même exception, il est possible de la propager:

private static void oneMove(Stack src, Stack dest)
  throws RuntimeException {
    dest.push( src.top() );
    src.pop();
}

Deux types d'exceptions§

En général, le compilateur s'assure qu'un bloc de code susceptible de lever une exception propage l'exception avec throws ou l'attrape avec try/catch et affiche un message d'erreur si ce n'est pas le cas. Les exceptions qui déclenchent un tel comportement sont vérifiées (checked exceptions).

Il existe cependant des exceptions, matérialisées par des instances de Error, de RuntimeException et de leurs classes dérivées, qui ne sont pas vérifiées (unchecked exceptions). Elles doivent être réservées aux événements après lesquels le programme ne peut plus continuer à fonctionner normalement (bug ou ressource externe nécessaire manquante).

Personnaliser l'exception§

Avoir sa propre classe d'exception, même vide, permet de distinguer cette exception des autres par différents blocs catch.

public class EmptyStackException extends RuntimeException {}
public int pop() throws EmptyStackException {
    if ( myNode == null )
        throw new EmptyStackException();
    else
        myNode = myNode.next();
}

Celui qui n'en fait pas assez§

Ne jamais écrire un code qui masque les exceptions.

//PAS BIEN
try {
  unCodeQuiLeveUneException();
} catch(Exception e) {
  /* Aucune action, ce qui masque les erreurs */
}

Préférez au moins:

try {
  unCodeQuiLeveUneException();
} catch(Exception e) {
  /* affiche l'empilement des appels qui ont mené à l'erreur */
  e.printStackTrace();
}

Celui qui en fait trop§

N'entourez pas chaque instruction d'un bloc try/catch: ça ne sert à rien et va à l'encontre de l'objectif qui est de séparer le bloc d'instructions principal, des instructions relevant de la gestion des exceptions pouvant survenir dans ce bloc, afin d'obtenir un code plus lisible et plus facile à réutiliser.

//PAS BIEN
try {
  unCodeQuiLeveUneExceptionA();
} catch(ExceptionA e) {
  e.printStackTrace();
}
try {
  unCodeQuiLeveUneExceptionB();
} catch(ExceptionB e) {
  e.printStackTrace();
}

Ex.3. Gestion des exceptions (15 min)§

Ce qu'il faut retenir§

Ce que vous devez savoir faire§