|
Ajouts syntaxiques de Java 5.0 |
Enumération
import static
Liste d'arguments variable
Autoboxing / auto-unboxing
Boucle itérative
Généricité
Annotations
Ce chapitre présente un aperçu des nombreuses nouveautés syntaxiques apportées au langage Java à partir de Java 5.0 (ou 1.5), à savoir :
- les énumérations de constantes avec le mot-clé enum
- import static pour éviter d'écrire systématiquement l'identificateur d'une classe devant l'un de ses membres static
- les listes d'arguments variables
- l'autoboxing pour faciliter la création d'une instance de classe d'emballage à partir d'une valeur de type primitif
- la généricité et les boucles itératives pour simplifier la gestion des éléments d'un tableau ou d'une collection
- la possibilité d'ajouter des annotations ou metadata à une classe.
Le nouveau mot-clé enum permet d'énumérer une liste homogène de constantes, comme en C++ et en C#. Dans les faits, une énumération Java, appelée aussi une énumération de type sûr, est une classe qui définit un ensemble de constantes dont le type est la classe elle-même. Le langage Java a été aussi enrichi pour permettre de tester les valeurs d'une énumération avec l'instruction switch.
Par exemple, les deux applications suivantes effectuent un test avec l'instruction switch, l'une sur un ensemble de constantes définies dans une classe, l'autre sur une énumération.
Avec classe de constantes
Avec énumération // Déclaration d'une classe de constantes class Titre { public static final int MONSIEUR = 0; public static final int MADAME = 1; public static final int MADEMOISELLE = 2; }; class AfficherTitre { public static void main(String[] args) { int titreContact = Titre.MONSIEUR; String message = "Titre " + titreContact + " = "; switch (titreContact) { case Titre.MONSIEUR : message += "Mr"; break; case Titre.MADAME : message += "Mme"; break; case Titre.MADEMOISELLE : message += "Melle"; break; } // Affiche Titre 0 = Mr System.out.println (message); } } // Déclaration d'une énumération enum Titre {MONSIEUR, MADAME, MADEMOISELLE}; class EnumerationTitre { public static void main(String[] args) { Titre titreContact = Titre.MONSIEUR; String message = "Titre " + titreContact + " = "; switch (titreContact) { case MONSIEUR : message += "Mr"; break; case MADAME : message += "Mme"; break; case MADEMOISELLE : message += "Melle"; break; } // Affiche Titre MONSIEUR = Mr System.out.println (message); } }
Le contrôle de type sur une variable de type enum est plus stricte en Java qu'en C/C++ car vous n'avez pas de possibilité de convertir une variable de type enum en type int.
La clause import static permet d'importer les membres static d'une classe, pour vous éviter par exemple de citer la classe System pour utiliser son champ out :
import static java.lang.System.*;
Une liste d'arguments variable permet à une méthode de recevoir en dernier paramètre un nombre variable de valeurs (zéro ou plus). Une telle liste est déclarée en précédant le dernier paramètre de trois points ..., ce paramètre étant en fait un tableau.
Par exemple, la méthode additionner() de la classe suivante peut prendre un nombre variable d'entiers en paramètre :import static java.lang.System.*; class AdditionnerArgumentsVariable { public static int additionner(int x, int ... tab) { for (int i = 0; i < tab.length; i++) x += tab [i]; return x; } public static void main(java.lang.String [] args) { out.println ("1 + 2 = " + additionner(1, 2)); out.println ("1 + 2 + 3 + 4 = " + additionner(1, 2, 3, 4)); } }
Java simplifie grandement le traitement des éléments d'une liste d'arguments variable par rapport au C, puisque c'est en fait un simple tableau ; par contre, vous êtes obligé de spécifier un type pour les éléments de cette liste. Si vous tenez à accepter n'importe quel type objet, vous pouvez toujours utiliser la classe Object comme type.
La création d'une instance d'une classe d'emballage à partir d'une valeur du type primitif correspondant est simplifiée grâce à l'autoboxing (littéralement mise en boîte automatique). Cette fonctionnalité évite d'écrire explicitement l'appel à new ClasseEmballage pour créer un objet d'une classe d'emballage.
Par exemple, l'instruction :
Integer zero = 0;
sera automatiquement traduite par le compilateur par l'instruction :
Integer zero = new Integer(0);Symétriquement, l'auto-unboxing évite de faire appel explicitement à la méthode d'une classe d'emballage qui renvoie la valeur de type primitif stockée par un objet de ce type.
Par exemple, l'instruction :
int x = zero;
sera automatiquement traduite par le compilateur par l'instruction :
int x = zero.intValue();
Cette fonctionnalité simplifie grandement la programmation, mais faîtes attention à ne pas en abuser involontairement, car chaque opération d'autoboxing implique la création d'un objet.
Par exemple, le remplacement du f minuscule du type float par un F majuscule dans le code suivant va provoquer la création de plusieurs objets :Float valeur = 0.2f; Float somme = valeur + 10;
La syntaxe de l'instruction for peut être simplifiée pour énumérer un à un les éléments d'un tableau.
Par exemple, la méthode additionner de la classe AdditionnerArgumentsVariable définie ci-dessus peut être simplifiée ainsi :public static int additionner(int x, int ... tab) { for (int val : tab) x += val; return x; }cette boucle signifiant pour chaque élément val de l'ensemble tab.
La généricité équivalente au template C++ est probablement la fonctionnalité la plus demandée dans Java depuis son origine : elle est utilisée par les classes de collection de données pour laisser le choix au programmeur de spécifier une classe différente d'Object comme classe des objets stockés. La classe des objets est spécifiée entre les symboles < et > qui suivent la classe de collection : par exemple Vector<Integer> représente une collection de classe Vector dans laquelle seuls des objets de classe Integer pourront être ajoutés.
La généricité simplifie aussi la consultation des éléments d'une collection car :
- elle évite de faire appel à l'opérateur de cast pour manipuler un élément de l'ensemble dans son type
- elle autorise le recours aux boucles itératives pour énumérer un à un les éléments d'un ensemble, sans faire appel explicitement à un indice de boucle ou aux méthodes de l'interface Enumeration.
Pour les collections de classe Hashtable, il faut spécifier la classe des clés et celle des éléments en séparant les classes par une virgule (par exemple, Hashtable<String,String> pour une collection contenant des clés et des éléments de classe String).
Les deux applications suivantes crée un ensemble d'objets de classe Vector, l'une sans préciser la classe des objets stockés dans l'ensemble, l'autre en précisant que cet ensemble ne peut contenir que des chaînes de caractères de classe String. La première application va déclencher une exception de classe ClassCastException dans la boucle énumérative sur l'objet de classe Object, tandis que la seconde application ne provoque pas d'erreur à l'exécution : le recours à la généricité a empêché dès la compilation d'ajouter à l'ensemble un objet dont la classe n'est pas String (ou une de ses sous-classes mais elle n'en a pas).
Sans généricité
Avec généricité import java.util.*; class AfficherPrenomsSansGenericite { public static void main (String args []) { // Création d'un ensemble d'objets Vector prenoms = new Vector(); prenoms.addElement("Thomas"); prenoms.addElement("Sophie"); // La méthode add n'interdit pas // d'ajouter n'importe quel objet prenoms.addElement(new Object()); // Enumération des objets de prenoms for (int i = 0; i < prenoms.size(); i++) { // Cast explicite obligatoire // pour manipuler l'objet dans son type String prenom = (String)prenoms.elementAt(i); System.out.println (prenom); } } } import java.util.*; class AfficherPrenomsAvecGenericite { public static void main (String args []) { // Création d'un ensemble capable // de ne stocker que des objets String Vector<String> prenoms = new Vector<String> (); prenoms.addElement("Thomas"); prenoms.addElement("Sophie"); // La méthode add interdit d'ajouter // un autre type d'objet // prenoms.addElement(new Object()); // Boucle itérative for (String prenom : prenoms) System.out.println (prenom); } }
A la différence des templates C++ qui génère une classe ou une méthode pour chaque instanciation avec un type différent entre < > , la généricité en Java utilise une seule classe par classe générique.
Pour une information complète sur la généricité, consultez le document Generics in the Java Programming Language.
Les annotations permettent d'ajouter des informations déclaratives avant la déclaration d'une classe, d'un champ, d'une méthode ou d'un constructeur grâce à des balises qui débutent par le symbole @ comme dans les commentaires javadoc ; par exemple, l'annotation @Override placée avant une méthode redéfinie force javac à vérifier sa signature. A la différence des commentaires javadoc, les annotations sont écrites en dehors de tout commentaire et sont enregistrées dans les fichiers .class ce qui permet de les exploiter à l'exécution de la JVM sans les programmes sources.
|