FAQ Langage JavaConsultez toutes les FAQ
Nombre d'auteurs : 42, nombre de questions : 297, dernière mise à jour : 19 septembre 2017 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur le forum Java de http://java.developpez.com ainsi que l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- Quels sont les différents mots-clés du langage Java ?
- Que signifient les mots-clés public, private et protected ?
- Que signifie le mot-clé void ?
- Comment faire une condition avec if-then-else ?
- Que signifie le mot-clé return ?
- Comment faire une boucle avec for ?
- Comment faire une boucle avec while et do-while ?
- Comment faire un switch ?
- Que signifie le mot-clé static ?
- Puis-je utiliser des méthodes statiques dans une interface ?
- Que signifie le mot-clé final ?
- Que signifient les mots-clés this et super ?
- Que signifie le mot-clé strictfp ?
- Que signifie le mot-clé transient ?
- Que signifie le mot-clé volatile ?
- Java dispose-t-il d'un goto ?
- Comment utiliser les mots-clés break et continue ?
- Comment fonctionnent les Varargs (nombre d'arguments variable) ?
- Que signifie le mot-clé import ?
- Qu'est-ce que l'import static ?
- Quelle est la différence entre « import » et « import static » ?
- Qu'est-ce que l'opérateur ternaire "?" ?
- Que veut dire « deprecated » ?
- Comment tester si une variable est une instance d'un type donné ?
- Que signifie le mot-clé throw ?
- Que signifie le mot-clé throws ?
- Que signifie le mot-clé try ?
- Que signifie le mot-clé catch ?
- Que signifie le mot-clé finally ?
Un mot-clé est tout simplement un mot qui a été réservé dans la grammaire du langage pour une utilisation spéciale par ce langage ; vous ne pouvez donc pas employer des mots-clés comme noms de variable, noms de classe ou tous autres éléments qui peuvent être déclarés.
Pour avoir une liste de tous les mots-clés du langage Java et de leurs significations, vous pouvez lire cet article ou la référence sur le site d'Oracle.
Ces trois mots-clés du langage Java (public, private, protected) définissent la portée d'une variable, d'une méthode ou d'une classe.
Il existe en fait quatre modificateurs d'accessibilité ; le quatrième est le modificateur dit par package-private. Pour ce dernier modificateur, on n'écrit rien : il n'y a pas de modificateur devant le nom de la variable, de la méthode ou de la classe. Attention, il ne faut pas confondre ce dernier modificateur avec le modificateur public.
Voici les caractéristiques de ces modificateurs, du plus permissif au plus restrictif :
Mot-clé | Portée | Remarques |
public | Les variables, méthodes ou classes publiques sont accessibles par tout objet. | Il ne peut y avoir qu'une seule classe publique par .java et celle-ci doit obligatoirement porter le nom du fichier .java |
Les variables, méthodes ou classes définies sans modificateur sont accessibles par toute classe appartenant au même package. | Attention : les variables sans modificateur ne sont pas accessibles aux classes filles définies dans un autre package. | |
protected | Les variables, méthodes ou classes définies comme protégées ne sont accessibles que par les classes filles et classes du même package. | |
private | Les variables, méthodes ou classes définies comme privées ne sont accessibles que par la classe dans laquelle elles sont définies. | Il est fortement conseillé de déclarer comme privés tous les attributs d'une classe, et de créer des méthodes de type getter et setter pour y accéder. |
Naturellement, toute méthode, variable ou classe est accessible dans la classe ou elle est définie.
Remarque : il y a deux cas particuliers où l’absence de mot-clé de visibilité ne correspond pas à une visibilité package-private :
- tous les membres (attributs et méthodes) d'une interface ou d'une annotation sont obligatoirement public ;
- tous les constructeurs d'une Enum sont obligatoirement private.
Le mot-clé void (avec un petit v) signifie littéralement « rien » ou « néant ». Ce mot-clé indique qu'une méthode ne retourne aucune valeur et sert donc à distinguer les méthodes qui ne retournent pas de valeur (appelées « procédures » dans d'autres langages de programmation) de celles qui en retournent une (appelées « fonctions » dans d'autres langages).
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | public void maMethode1() { [...] } public int maMethode2() { [...] return 0; } |
Ici, maMethode1() ne retourne pas de valeur, tandis que ma maMethode2() retourne un entier qu'il est possible d'affecter dans une variable.
Code Java : | Sélectionner tout |
1 2 | int valeur1 = maMethode1(); // Impossible, ne compile pas. int valeur2 = maMethode2(); // Compile |
Attention : ne pas confondre le mot-clé void et la classe java.lang.Void (avec un grand V) qui permet de retourner la valeur null et rien d'autre.
Les conditions de type if-then-else se traduisent en Java de cette manière :
Code Java : | Sélectionner tout |
1 2 3 | if (condition) { // Code exécuté si condition respectée. } |
Ou encore, dans le cas où on effectue une action lorsque la condition n'est pas respectée :
Code Java : | Sélectionner tout |
1 2 3 4 5 | if (condition) { // Code exécuté si condition respectée. } else { // Code exécuté si condition non respectée. } |
Vous noterez qu'il n'y a pas de mot-clé then dans la syntaxe.
Il est possible d'empiler différentes conditions de cette manière
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | if (condition1) { // Code exécuté si condition respectée. } else if (condition2) { // Code exécuté si condition2 est respectée. } else if (condition3) { // Code exécuté si condtion3 est respectée. } else { // Code exécuté si condition3 non respectée. } |
Le mot-clé return permet de terminer une méthode et de la quitter. Lorsqu'une méthode ne retourne pas de valeur (déclarée void), le mot-clé return doit être utilisé tel quel sans spécifier de valeur. Lorsque cette méthode retourne une valeur, ce mot-clé doit être suivi d'une valeur de retour ; cela permet de faire remonter ce résultat dans la méthode appelante. Combiné avec des tests, le mot-clé return peut être utilisé pour sortir prématurément d'une méthode.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public void maMethode1() { [...] if (test) { return; // Cet appel court-circuite le reste de la méthode. } [...] // Ici le return est implicite, il n'est pas besoin de le spécifier. } public int maMethode1() { [...] if (test) { return 1; // Cet appel court-circuite le reste de la méthode. } [...] return 0; // Ici, il faut quand même retourner une valeur. } |
Attention : lorsqu'une méthode est déclarée comme retournant une valeur, contrairement à d'autres langages, il n'y a pas de valeur de retour implicite. En Java, vous devez explicitement déclarer toutes les valeurs de retour.
Le mot-clé return doit toujours être la dernière instruction d'un bloc. Si le mot-clé return est placé ailleurs dans le bloc, votre code ne compilera pas et vous obtiendrez une erreur indiquant que votre code n'est pas atteignable (unreachable statement).
Code Java : | Sélectionner tout |
1 2 3 | System.out.println("Toto"); return; // Ne compile pas. System.out.println("Tutu"); |
Il existe deux manières de créer des boucles for en Java.
For classique
Le for classique est la manière traditionnelle d'utiliser ce genre de boucle. La syntaxe à utiliser est la suivante :
Code Java : | Sélectionner tout |
1 2 3 | for (initialisation ; condition ; mise à jour) { // Code à exécuter dans la boucle. } |
- L'initialisation permet de configurer une ou plusieurs variables qui serviront en général d'indices lors de la boucle. L'initialisation est utilisée uniquement lors du démarrage de la boucle.
- La condition consiste en un ou plusieurs tests qui permettent de stopper la boucle. Ces conditions sont vérifiées au démarrage de la boucle et au début de chaque interaction. Les conditions peuvent porter sur des variables qui ne sont pas décrites dans l'initialisation.
- La mise à jour permet de changer la valeur (incrémentation, décrémentation, etc.) d'une ou plusieurs variables à la fin d'une itération. Les mises à jour peuvent porter sur des variables qui ne sont pas décrites dans l'initialisation ou testées par les conditions.
Chacune des parties est séparée de la suivante par un point-virgule « ; ». Il est important de bien vérifier ce que vous écrivez dans chacune de ces trois parties sous peine d'avoir des boucles qui ne démarrent jamais, dont les mises à jour ne se passent pas comme prévu ou même qui itèrent de manière infinie (boucle infinie ou infinite loop).
Prenons un exemple de boucle simple :
Code Java : | Sélectionner tout |
1 2 3 | for (int index = 0 ; index < 3 ; index++) { System.out.println(index); } |
Ici, ce bout de code permet de faire varier la variable index de la valeur 0 à la valeur 3. La boucle se terminera lorsque la valeur 3 sera atteinte. La sortie de ce bout de code est :
Code Console : | Sélectionner tout |
1 2 3 | 0 1 2 |
Prenons un autre exemple :
Code Java : | Sélectionner tout |
1 2 3 | for (int index = 2 ; index >= 0 ; index--) { System.out.println(index); } |
Ici, ce bout de code permet de faire varier la variable index de la valeur 2 à la valeur -1. La boucle se terminera lorsque la valeur -1 sera atteinte. La sortie de ce bout de code est :
Code Console : | Sélectionner tout |
1 2 3 | 2 1 0 |
Chaque partie de la déclaration est optionnelle et peut être omise : il suffit de la laisser vide, mais ce sera à vos propres risques. Ainsi, il est tout à fait possible d’écrire :
Code Java : | Sélectionner tout |
1 2 3 | for (;;) { // Code à exécuter dans la boucle. } |
Ce qui provoquera une boucle infinie.
Il est possible de déclarer plusieurs variables dans l'initialisation, en les séparant par des virgules « , ». Ces variables sont forcements toutes du même type que la première variable déclarée. Par exemple :
Code Java : | Sélectionner tout |
1 2 3 | for (int variableA = 0, variableB = 5 ; condition ; mise à jour) { // Code à exécuter dans la boucle. } |
Il est de même possible de faire une mise à jour qui porte sur plusieurs variables, en les séparant par des virgules « , ».
Code Java : | Sélectionner tout |
1 2 3 | for (initialisation ; condition ; variableA ++, variableB -= 7) { // Code à exécuter dans la boucle. } |
Il n'est pas possible de spécifier plusieurs conditions en les séparant par des virgules. Il suffit d’écrire plusieurs conditions et de les composer avec des opérateurs booléens tels que && (ET) ou || (OU).
Attention : trop abuser de cette syntaxe tend à rendre la lecture de la bouche difficile et il est alors plus facile de commettre des erreurs.
For-each
Depuis Java 1.5, il est possible d'utiliser le mot-clé for dans une boucle nommée enhanced for loop (boucle for améliorée) également appelée for-each dans d'autres langages. Ce type de boucle effectue une itération automatique sur un ensemble de valeurs ; il n'est donc pas besoin de manipuler un indice manuellement comme dans le for classique. Si un conteneur de données est un tableau ou hérite de l'interface java.lang.Iterable<T>, il est possible de faire une boucle for-each en utilisant la syntaxe suivante :
Code Java : | Sélectionner tout |
1 2 3 | for (valeur : conteneur) { // Code à exécuter dans la boucle. } |
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 | final int[] valeurs = { 1, 2, 3 }; for (final int valeur : valeurs) { System.out.println(valeur); } |
Ou encore :
Code Java : | Sélectionner tout |
1 2 3 4 | final List<Integer>valeurs = Arrays.asList(1, 2, 3); for (final int valeur : valeurs) { System.out.println(valeur); } |
Ces deux bouts de code auront comme sortie :
Code Console : | Sélectionner tout |
1 2 3 | 1 2 3 |
Ici, dans le premier code valeurs est un tableau d'entiers tandis que dans le second bout de code c'est un objet de type List<Integer> qui étend donc l'interface Iterable<Integer>. Il est donc possible d'utiliser la syntaxe for-each dans les deux cas.
L'instruction while exécute un bloc d'instructions tant que la condition est respectée.
Code Java : | Sélectionner tout |
1 2 3 | while (expression) { // Code à exécuter dans la boucle. } |
L'instruction do-while est identique à la précédente sauf qu'au moins un bloc d'instructions est exécuté même si la condition n'est pas respectée.
Code java : | Sélectionner tout |
1 2 3 | do { // Code à exécuter dans la boucle. } while (expression); |
Attention : dans une boucle while ou do-while, vous devez vous-même gérer les conditions qui permettent de quitter la boucle. Le code suivant par exemple provoquera une boucle infinie (infinite loop) :
Code Java : | Sélectionner tout |
1 2 3 | while (true) { // Code à exécuter dans la boucle. } |
La différence entre while et do-while tient dans le fait que do-while évalue la condition à la fin. Ainsi, dans avec do-while le bloc d'instruction est au moins exécuté une fois.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | final int fin = 0; int i = 0; while (i < fin) { System.out.println("i " + i); i++; } int j = 0; do { System.out.println("j " + j); j++; } while (j < fin); |
Ici seule la seconde boucle affichera une sortie puisque son instruction est exécutée au moins une fois.
L'instruction switch permet de faire un saut dans le code en fonction d'une valeur constante qui est définie par une instruction case (qui fonctionne un peu comme un label). Le label default permet de définir un cas de figure par défaut.
Literal
L'instruction switch accepte presque tous les types de base : byte, char, short, int, long, float, double. Le type boolean n'est pas supporté.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | int myVar = [...] switch (maVar) { case 1: [...] // Instructions 1. case 2: [...] // Instructions 2. break; case 3: default: [...] // Instructions 3. } |
Ici, si maVar vaut :
- 1 - les blocs d'instructions « Instructions 1 » et « Instructions 2 » sont exécutés séquentiellement. L'instruction break permet de quitter le bloc switch sans exécuter le bloc « Instructions 3 ».
- 2 - le bloc d'instructions « Instructions 2 » est exécuté. L'instruction break permet de quitter le bloc switch sans exécuter le bloc « Instructions 3 ».
- 3 ou une autre valeur - le bloc d'instructions « Instructions 3 » est exécuté.
L'instruction case n'accepte que des constantes ; ainsi le compilateur reportera l'erreur case expressions must be constant expressions si jamais vous essayez de faire :
Code Java : | Sélectionner tout |
1 2 3 4 5 | int a = 1; switch (maVar) { case a: // Interdit. [...] } |
Cependant, il est possible déclarer la variable a avec le mot-clé final pour la déclarer en tant que constante :
Code Java : | Sélectionner tout |
1 2 3 4 | final int a = 1; switch (maVar) { case a: // Fonctionne. } |
Chaine de caractères
L'instruction switch supporte les String depuis le JDK7. Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | String maString = [...] switch (maString) { case "A": [...] break; case "B": [...] break; default: [...] } |
Pour des versions de Java antérieures au JDK7, il n'est pas possible de faire un switch sur un String. Il faudra passer par une séquence de constructions if-then-else-if :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 | if ("A".equals(maString)) { [...] } else if ("B".equals(maString)) { [...] } else { [...] } |
Attention : le switch sur des instances de String s’accommode mal de la valeur null.
Enum
Il est possible d'utiliser des enums dans un switch. Dans ce cas précis, les valeurs des labels doivent reprendre texto les valeurs définies dans l'enum sans les préfixer par le nom de leur classe :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public enum Priority { ALWAYS, SOMETIMES, NEVER; } Priority maPriorite = [...] switch (maPriorite) { case ALWAYS: // Et non pas Priority.ALWAYS [...] break; case SOMETIMES: // Et non pas Priority.SOMETIMES [...] break; case NEVER: // Et non pas Priority.NEVER [...] break; } |
Attention : le switch sur des enums s’accommode mal de la valeur null.
Le mot-clé static est utilisable pour des variables, méthodes, classes internes ou blocs de code.
Devant une variable ou méthode :
Le mot-clé static devant une variable (ou méthode) indique que celle-ci n'appartient pas à une instance particulière de la classe. Les variables ou méthodes statiques appartiennent à la classe elle-même. On peut ainsi les utiliser sans avoir une instance créée. De nombreuses classes ont des membres ou méthodes statiques. Par exemple la classe java.lang.Math :
Code Java : | Sélectionner tout |
1 2 3 4 | System.out.println(Math.PI); // Affiche la valeur de PI. System.out.println(Math.abs(-1)); // Affiche la valeur absolue de -1. |
- on peut aussi manipuler une variable ou méthode statique à partir d'une instance de la classe ;
- pour rendre des variables statiques comme des constantes, il faut combiner le mot-clé static avec le mot-clé final ;
- les méthodes statiques, étant indépendantes de toute instance, n'ont pas accès aux variables ou méthodes non statiques.
Devant un bloc de code :
Le mot-clé static devant un bloc de code indique que celui-ci ne sera exécuté qu'une fois. L'exécution se fait lors du chargement de la classe par le ClassLoader. On peut utiliser ces blocs, par exemple, pour initialiser des variables statiques complexes.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | public class MaClasse { public static Map<String, String> uneVariableStatique = new HashMap<String, String>(); static{ // Initialisation du contenu de uneVariableStatique lors du chargement de la classe. uneVariableStatique.put("une clef","une valeur"); uneVariableStatique.put("une autre clef","une autre valeur"); // Etc . } } |
Devant une classe interne :
Pour plus d'informations sur ce cas, reportez-vous à la QR Quels sont les différents types de classes internes (nested classes) ? .
Depuis le JDK8, les méthodes statiques sont autorisées dans les interfaces. Dans les versions antérieures, seule la définition de variables statiques était autorisée.
Dans l'exemple ci-dessous, une interface Person déclare une méthode statique sayHello().
Code Java : | Sélectionner tout |
1 2 3 4 5 | interface Person { static void sayHello() { System.out.println("Hello there!"); } } |
Le mot-clé final est utilisable pour des variables, méthodes, classes, classes internes ou des classes internes statiques.
Devant une méthode :
On indique que cette méthode ne pourra plus être redéfinie dans une classe fille. Ce qui entraine une certaine optimisation dans les appels à cette méthode.
Code Java : | Sélectionner tout |
1 2 3 4 | // Aucune classe fille ne peut redéfinir cette méthode. public final void doClick() { [...] } |
Devant une classe :
On ne peut pas créer de classe dérivée de celle-ci. Par exemple, il est impossible de dériver une classe à partir de la classe String de la bibliothèque de base, car elle est décrite d'une manière similaire à :
Code Java : | Sélectionner tout |
1 2 3 4 | // Il est impossible d’étendre cette classe. public final class String { [...] } |
Cela peut aussi bien s'appliquer aux classes normales, qu'aux classes internes ou internes statiques :
Devant une variable membre ou une variable locale :
La variable ne peut plus être modifiée après son initialisation, et doit obligatoirement être initialisée une fois (et une seule fois).
Pour une variable membre, elle peut être initialisée de plusieurs manières.
- Par une déclaration en ligne :
Code java : Sélectionner tout private final int i = 5;
- Par un bloc d'initialisation :
Code java : Sélectionner tout 1
2
3
4private final int i; { i = 5; }
- Par un constructeur :
Code java : Sélectionner tout 1
2
3
4
5private final int i; public Exemple() { i = 5; }
Pour une variable membre statique, elle peut être initialisée :
- Par une déclaration en ligne :
Code java : Sélectionner tout private static final int X = 5;
- Par un bloc d'initialisation statique :
Code java : Sélectionner tout 1
2
3
4private static final int X; static { X = 5; }
Pour une variable locale :
Code java : | Sélectionner tout |
1 2 3 4 | public void methode() { final float flottant = 0.2f; flottant = 0.5f // Interdit. } |
Devant un paramètre d'une méthode : empêche l'attribution d'une nouvelle valeur au paramètre.
Par exemple :
Code java : | Sélectionner tout |
1 2 3 4 5 6 | public void methode(final List<Object> liste, final int entier) { entrier = 0; // Interdit. liste = new ArrayList<Object>(); // Interdit. final float flottant = 0.2f; flottant = 0.5f // Interdit. } |
Pour une variable locale ou pour un paramètre de méthode, cela permet également de référencer cette variable dans une classe anonyme ou encore une expression lambda qui serait définie dans la méthode.
Les mots-clés this et super désignent respectivement des références sur l'instance courante et sur la classe mère. Voici un exemple qui devrait mettre en valeur cette définition plutôt succincte :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public MaClasse extends ClasseMere { private String attribut; // On peut accéder aux constructeurs de la super-classe. public MaClasse(String uneValeur){ super(uneValeur); // On appelle ici le constructeur de la classe mère qui prend en paramètre une String. // Cet appel, s'il a lieu d’être, est toujours sur la première ligne du constructeur. } // On peut aussi accéder aux constructeurs de la classe elle-même. public MaClasse(){ this("une valeur par défaut"); // On appelle ici le constructeur défini un peu plus haut. // Cet appel, s'il a lieu d’être, est toujours sur la première ligne du constructeur. } // En général l'appel à this est superflu lors d'appels à une méthode. public void uneMethode() {} public void doubleAppel(){ // Les deux lignes suivantes sont équivalentes. this.uneMethode(); uneMethode(); } // L'appel à this peut être utile pour bien différencier les variables de classe des paramètres ou variables de méthodes. public void uneMethode(String attribut){ this.attribut = attribut; // Ici, la variable de classe prend la valeur de la variable passée en paramètre de la méthode. } // On peut aussi faire appel aux méthodes de la super-classe. public void uneAutreMethode(){ // On peut faire quelque chose en plus avant. super.uneAutreMethode(); // Mais aussi après. } } |
À noter que, dans le cas d'une classe interne (non statique), le mot-clé this permet également de récupérer l'instance de la classe englobante :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class Englobante { private Object attribut; public final class Interne { private Object attribut; private Interne() { Englobante.this.attribut = this.attribut; // Le premier this fait référence à la classe englobante. // Le second this fait référence à la classe interne. } } } |
Ces deux mots-clés sont très liés au concept d'héritage.
Le mot-clé strictfp, qui est une abréviation de Strict floating point, s'applique en tant que modificateur d'accès. Ou plus simplement, on l'utilise de la même manière que les mots-clés public ou synchronized. Avec quelques restrictions : strictfp s'applique en tant que modificateur de classes, d'interfaces ou de méthodes d'une classe et en aucun cas au constructeur ou aux méthodes d'une interface. L'entité affectée est alors dite « FP-strict ».
Effet
Comme son nom l'indique, strictfp agit sur les opérations en virgule flottante. C'est-à-dire sur les types primitifs double et float.
Java effectue les calculs en garantissant une priorité de la gauche vers la droite.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | /** classe FP-strict */ public strictfp class FPDemo { public static void main(String[] args) { double d = 8e+307; /** affiche 4 * d /2 donc 2 * d */ System.out.println(4 * d / 2); /** affiche 2 * d */ System.out.println(2 * d); } } |
Notons que le mot-clé oblige l'implémentation de la JVM à évaluer l'expression tel que prévu dans la spécification du langage. Ne pas faire usage de ce mot-clé ne garantit pas que la JVM réalisera ce calcul de la sorte. Une JVM peut en effet avoir le droit, si la méthode n'est pas FP-strict, d'utiliser des types intermédiaires différents pour éviter de provoquer un dépassement de capacité ou pour s'adapter à l'architecture de la machine. Dans ce cas les deux expressions pourraient, en fonction de la JVM, produire des résultats différents.
Conclusion : le mot-clé strictfp permet de garantir le même calcul quelle que soit la machine virtuelle sur laquelle l'opération est effectuée.
Le mot-clé transient (éphémère ou transitoire) est lié à la sérialisation des classes Java. Il permet d'interdire la sérialisation de certaines variables d'une classe.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | // La classe que nous allons sérialiser. class Writeable implements java.io.Serializable { // Entier transient. public transient int var1 = 4; // Entier normal. public int var2 = 19; } |
Ce mot-clé trouve des applications dès lors qu'une donnée sensible ne doit en aucun cas apparaitre dans un fichier. Un mot de passe par exemple. Mais ce mot-clé peut également permettre de « remettre à zéro » certaines valeurs. Dans le cas d'un jeu, on pourra ainsi ne pas sauvegarder le temps de jeu depuis le début de la partie.
Le mot-clé volatile est utilisé sur les variables qui peuvent être modifiées de manière asynchrone. C'est-à-dire que plusieurs threads peuvent y accéder simultanément. Ces accès peuvent être pour la lecture et/ou la modification du contenu.
En indiquant que la variable est volatile, on oblige la JVM à rafraîchir son contenu à chaque fois qu'elle est utilisée. On est ainsi certain que la valeur de la variable n'est pas une valeur mise en cache, mais bel et bien sa valeur exacte. Ainsi chaque thread a accès à la valeur la plus récente de la variable.
Remarque : ce mot-clé est relativement peu utilisé.
Bien que goto soit un mot réservé de Java, on ne le trouve pas dans le langage ; Java n'a pas de goto. Le mot-clé goto est aussi ancien que les langages de programmation. En effet, goto a été le premier moyen de contrôle des programmes dans les langages d'assemblage : « si la condition A est satisfaite, alors sauter ici, sinon sauter là ». Lorsqu'on lit le code assembleur finalement généré par n'importe quel compilateur, on voit qu'il comporte beaucoup de sauts.
Break et continue
Cependant, il existe quelque chose qui ressemble à un saut, lié aux mots-clés break et continue. Ce n'est pas vraiment un saut, mais plutôt une manière de sortir d'une instruction d'itération.
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | while(true) { // Instructions. [...] if (condition1) { // Quitte la boucle. break; } if (condition2) { // Retourne au début de la boucle. continue; } // Instructions. [...] } |
Comme nous l'avons vu, il n'y a pas de goto en Java, mais il est possible d'associer un label à une instruction de boucle. Ce label, utilisé en conjonction avec l'instruction break, permet de savoir à quel niveau le break sera effectif.
Un label est un identifiant suivi de : (deux-points) et qui se place devant l'instruction de la boucle.
Voici un exemple :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | Boucle1: while(true) { System.out.println("Boucle 1"); Boucle2: for(int ind=0; ind < 10; ind++) { System.out.println("Boucle 2"); Boucle3: while(true){ System.out.println("Boucle 3"); break Boucle2; } } break; } |
À votre avis, qu'affiche l'exécution de ce morceau de code ?
Remarque : le label peut aussi être utilisé en conjonction avec le mot-clé continue. De la même manière, le label indique à quel niveau de boucle le continue s'applique.
Les varargs, ou ellipse, sont un concept qui permet de créer des méthodes (ou des constructeurs) avec un nombre d'arguments variable. On utilise pour cela trois points (...) après le type des arguments, par exemple la méthode suivante accepte un nombre quelconque de String :
Code Java : | Sélectionner tout |
1 2 3 | public void method (String... args) { // } |
À l'intérieur de la méthode, le paramètre args est un tableau contenant les différents paramètres passés à la méthode. Ainsi, cette méthode peut s'utiliser de la manière suivante :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | // Avec 1 paramètre : method ("param1"); // Avec plusieurs paramètres : method ("param1", "param2", "param3"); // Sans paramètre : method (); |
En réalité, il ne s'agit ni plus ni moins qu'une nouvelle manière de déclarer une méthode avec un tableau en paramètre. En effet, pour le compilateur, cette déclaration correspond à la déclaration d'une méthode avec un tableau de String (String[]) en paramètre. Et lors de son utilisation, les différents paramètres de l'ellipse sont automatiquement stockés dans un tableau. Ainsi, les exemples d'utilisations ci-dessus correspondent en réalité au code suivant :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | // Avec 1 paramètre : method (new String[]{"param1"}); // Avec plusieurs paramètres : method (new String[]{"param1", "param2", "param3"}); // Sans paramètres : method (new String[]{}); |
Attention : on ne peut toutefois utiliser qu'un seul type d'argument variable par méthode, et il doit obligatoirement être en dernière position dans la liste des paramètres.
- Tutoriel : J2SE 1.5 Tiger, l'ellipse par Lionel Roux.
Le mot-clé import permet l'utilisation du nom court d'une classe au lieu de son nom long. Ainsi, pour les utilisateurs de C++, il est a rapprocher d'un using namespace plutôt que d'un #include.
Par exemple, il est tout à fait possible d’écrire :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | mon.paquet.a.moi.MaClasse toto = new mon.paquet.a.moi.MaClasse(); [...] public void maMethode1(mon.paquet.a.moi.MaClasse parametre1) { [...] } public mon.paquet.a.moi.MaClasse maMethode2() { [...] } |
Cependant, il devient assez pénible à la longue de devoir écrire le nom long de la classe partout dans le code ; encore plus quand le code est très long.
En utilisant un import dans l’entête du fichier, il est possible désormais d'utiliser le nom court de la classe partout où celle-ci est référencée. Notre code devient donc :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import mon.paquet.a.moi.MaClasse; [...] MaClasse toto = new MaClasse(); [...] public void maMethode1(MaClasse parametre1) { [...] } public MaClasse maMethode2() { [...] } |
Lors de la compilation, le compilateur remplacement automatiquement toutes les occurrences du nom court MaClasse par le nom long mon.paquet.a.moi.MaClasse.
Note : il est également possible d'utiliser un import wildcard (large) qui permettra d'utiliser le nom court de toutes les classes de ce package :
Code Java : | Sélectionner tout |
import mon.paquet.a.moi.*;
L'importation statique permet d'importer les éléments statiques d'une classe afin d'alléger l'écriture du code. Cela permet en effet de ne pas préfixer les éléments statiques par le nom de la classe. Par exemple, les deux codes suivants sont identiques, mis à part que le second utilise une importation statique pour accéder aux méthodes de la classe java.lang.Math :
Code Java : | Sélectionner tout |
1 2 3 4 5 | public Class Test { public void calcul (int i) { Math.round(Math.cos(i*(Math.PI/6)-Math.PI/2)*Math.E); } } |
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 | import static java.lang.Math.*; public Class Test { public void calcul (int i) { round(cos(i*(PI/6)-PI/2)*E); } } |
Ce mécanisme est proche du mot-clé using namespace du C++. Toutefois, il est conseillé de limiter son utilisation afin de faciliter la lecture du code et éviter des conflits potentiels. On peut pour cela importer seulement l'élément qui nous intéresse, par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | import static java.lang.System.out; public Class Test { public void print () { out.println("Message d'information"); System.err.println("Message d'erreur"); } } |
Les mots-clés import et le import static n'ont pas la même fonction.
Le mot-clé import opère sur une classe (ou un ensemble de classes via la notation *) et permet d'éviter de spécifier le package de la classe à chaque fois qu'on l'utilise (en partant du principe que l'on se trouve dans un paquetage différent de celui contenant la classe actuelle).
Le mot-clé import static a un fonctionnement similaire, mais pour les méthodes et les attributs statiques d'une classe ou d'une interface et les membres d'une enum. En effet, il permet d'éviter de spécifier la classe de la méthode ou de l'attribut statique à chaque fois qu'on l'utilise (en partant du principe que l'on se trouve dans une classe différente de celle contenant la méthode ou l'attribut).
Illustration
Soit les classes package_a.ClasseA et package_b.ClasseB.
Pour « utiliser » la classe ClasseA dans la classe ClasseB, il faut normalement spécifier le package comme suit :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | package package_b; public class ClasseB { private package_a.ClasseA a; public CLasseB() { a = new package_a.ClasseA(); } } |
Ici, nous avons dû utiliser le nom long de la classe. Utiliser le mot-clé import permet de supprimer cet inconvénient en indiquant à l'avance dans quel package se situe la classe ClasseA et permet donc d'écrire :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | package package_b; import package_a.ClasseA; public class ClasseB { private ClasseA a; public CLasseB() { a = new ClasseA(); } } |
Ici, nous avons pu utiliser le nom court de la classe. On se retrouve avec la même écriture que si la classe ClasseA était dans le même package que la classe ClasseB.
Supposons maintenant que la classe ClasseA possède la méthode statique suivante :
Code Java : | Sélectionner tout |
1 2 3 | public static void staticMethod() { [...] } |
Pour l'appeler depuis la classe ClasseB, il faut normalement écrire
Code Java : | Sélectionner tout |
ClasseA.staticMethod();
Ici, nous avons référencé le nom de la méthode en utilisant le nom de la classe. En faisant un import static de la méthode, on se retrouve comme si la méthode statique faisait partie de la classe ClasseB ; ce qui nous permet d'écrire :
Code Java : | Sélectionner tout |
1 2 3 4 5 | import static package_a.ClasseA.staticMethod; [...] staticMethod(); |
Ces deux clauses d'importation sont indépendantes, si je ne fais que le import, je pourrais écrire :
Code Java : | Sélectionner tout |
ClasseA
mais je devrais écrire :
Code java : | Sélectionner tout |
ClasseA.staticMethod();
À l'inverse je pourrais très bien ne faire que l'import static et je me retrouverais à devoir écrire :
Code Java : | Sélectionner tout |
package_a.ClasseA
mais à pouvoir écrire directement :
Code Java : | Sélectionner tout |
staticMethod();
En résumé il est important de bien retenir que :
- le mot-clé import ne permet la simplification d'écriture que pour les classes ;
- le mot-clé import static ne permet la simplification d'écriture que pour les méthodes et les attributs statiques d'une classe ou interface et les membres d'une enum ;
- les mots-clés import et import static sont indépendants l'un de l'autre.
On considère souvent l'opérateur ternaire "?" comme une syntaxe réduite de l'instruction if traditionnelle. Mais c'est avant tout un opérateur au sens où il produit une valeur.
Code Java : | Sélectionner tout |
(condition) ? résultat_1 : résultat_2
Si la condition est vérifiée alors le résultat est résultat_1 ; sinon, c'est résultat_2.
À noter que résultat_1 est évalué seulement si la condition est vérifiée, et que résultat_2 est évalué seulement si la condition n'est pas vérifiée.
Cet opérateur fournit un moyen compact d'écrire une affectation conditionnée:
Code Java : | Sélectionner tout |
String chaine = (nouvelleChaine != null) ? nouvelleChaine : "";
à la place de :
Code Java : | Sélectionner tout |
1 2 3 4 | String chaine = ""; if (nouvelleChaine != null) { chaine = nouvelleChaine; } |
Attention : utilisé abusivement, il devient rapidement illisible.
Lorsqu'un membre, une méthode ou une classe sont qualifiés de deprecated, cela signifie que ce membre, cette méthode ou cette classe sont dépréciés ou encore obsolètes. Ce membre, cette méthode ou cette classe existent toujours pour des soucis de compatibilité ascendante, mais ils ne sont plus supportés et peut-être amenés à disparaître à l'avenir.
Pourquoi ?
Il existe plusieurs raisons pour qu'un membre, une méthode ou une classe soient marqués deprecated :
- le plus généralement il s'agit d'un renommage de l’entité. Certaines méthodes sont héritées des toutes premières versions de Java, les conventions de nommage n'étant pas toujours respectées à l’époque, certaines méthodes ont été renommées par la suite... (les exemples sont très fréquents dans Swing) ;
- quelques méthodes sont devenues obsolètes suite à une évolution de l'architecture de l'API (la gestion des dates par exemple) ;
- enfin, certaines méthodes se sont révélées dangereuses et ne doivent plus être utilisées. Les méthodes de la classe java.lang.Thread peuvent conduire à un état incohérent des objets ou un arrêt de l'application.
Comment déprécier une entité ?
Si vous créez une bibliothèque ou du code destiné à être utilisé par quelqu'un d'autre, vous pourriez être amené à déconseiller l'emploi d'une entité (membre, d'une méthode ou d'une classe).
Pour les versions les plus anciennes de Java (de Java 1.1 à Java 5), un simple tag javadoc @deprecated dans la documentation de cette entité suffit. Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | public class MaClass { /** * Une méthode dépréciée * @deprecated */ public void maMethodeDepreciee() { [...] } } |
Depuis Java 5, il est également possible d'utiliser l'annotation @Deprecated. Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 | public class MaClass { @Deprecated public void maMethodeDepreciee() { [...] } } |
Le tag javadoc @deprecated et l'annotation @Deprecated peuvent être utilisés en même temps.
L’opérateur de comparaison instanceof (littéralement « instance de ») permet de tester si une variable appartient à un type donné ou pas. Cet opérateur accepte uniquement en opérande de gauche une variable à tester de type référence de tableau ou d'objet ou à la valeur null. L’opérande de droite doit être un nom de classe, un type de tableau ou objet valide sur lequel tester la variable. Cette expression retourne un boolean indiquant si le test a réussi ou échoué.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | int[] t = { 1, 2, 3, 4}; boolean tEstUnTableauDEntier = t instanceof int[]; // tEstUnTableauDEntier contient la valeur true. boolean tEstUnObjet = t instanceof Object; // tEstUnObjet contient la valeur true. boolean tEstUnTableauDObject = t instanceof Object[]; // Compilation impossible. boolean tEstUneChaine = t instanceof String; // Compilation impossible. Object o = p; boolean oEstUnTableauDObject = o instanceof Object[]; // oEstUnTableauDObject contient la valeur false. boolean oEstUneChaine = o instanceof String; // oEstUneChaine contient la valeur false. |
Ici, t, un tableau, est une instance de la classe int[] qui étend elle-même la classe Object (toutes les classes Java héritent de cette classe) ; les deux premiers tests retournent donc la valeur true. Cependant, le 3e et le 4e tests ne compilent pas puisque la classe int[] n’hérite ni n'est un des ancêtres des classes Object[] et String : elles sont incompatibles et les classes Object[] et String sont non valides ; donc le compilateur rejette ces expressions. Nous pouvons cependant contourner le problème en stockant la valeur de t dans une variable o d'un type commun à toutes les classes (ici, Object).
De la même manière :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | Point p = new Point(); boolean pEstUnPoint = p instanceof Point; // pEstUnPoint contient la valeur true. boolean pEstUnObjet = p instanceof Object; // pEstUnObjet contient la valeur true. boolean pEstUnTableauDObject = p instanceof Object[]; // Compilation impossible. boolean pEstUneChaine = p instanceof String; // Compilation impossible. Object o = p; boolean oEstUnTableauDObject = o instanceof Object[]; // oEstUnTableauDObject contient la valeur false. boolean oEstUneChaine = o instanceof String; // oEstUneChaine contient la valeur false. |
Ici, p, un objet, est une instance la classe Point qui étend elle-même la classe Object (toutes les classes Java héritent de cette classe) ; les deux premiers tests retournent donc la valeur true. Cependant, le 3e et le 4e tests ne compilent pas puisque la classe Point n’hérite ni n'est un des ancêtres des classes Object[] et String : elles sont incompatibles et les classes Object[] et String sont non valides ; donc le compilateur rejette ces expressions. Nous pouvons cependant contourner le problème en stockant la valeur de p dans une variable o d'un type commun à toutes les classes (ici, Object).
Lorsqu'un test effectué avec instanceof réussit, alors il est possible d'effectuer un cast entre la valeur et la classe testée sans jamais générer d'exception de type ClassCastException :
Code Java : | Sélectionner tout |
1 2 3 4 | Object o = new Point(); if (o instanceof Point) { Point p = (Point)b; // Ce cast ne lève jamais de ClassCastException. } |
Lorsque la valeur à tester est null, le test échoue et retourne tout le temps la valeur false.
Par exemple ;
Code Java : | Sélectionner tout |
1 2 3 4 5 6 | int[] t = null; boolean tEstUnPoint = t instanceof Point; // tEstUnPoint contient la valeur false. boolean tEstUnObjet = t instanceof Object; // tEstUnObjet contient la valeur false. Point p = null; boolean pEstUnPoint = p instanceof Point; // pEstUnPoint contient la valeur false. boolean pEstUnObjet = p instanceof Object; // pEstUnObjet contient la valeur false. |
Le mot-clé throw (« jette » à l’impératif) est une instruction qui permet de lancer une exception.
Par exemple :
Code Java : | Sélectionner tout |
1 2 | IOException ex = new IOException("Erreur de lecture sur le fichier !"); throw ex; |
Ici, nous créons une nouvelle exception de type IndexOutOfBoundsException et nous la lançons immédiatement. Son lancement interrompt le flot d’exécution du programme et cette erreur va remonter la pile d’exécution des appels de fonctions jusqu'à ce qu'elle soit capturée. Suivant le type de l'exception, il peut être nécessaire de la déclarer dans la signature de la méthode en y ajoutant le mot-clé throws (avec un s à la fin).
Le mot-clé throws (« jette » à la troisième personne du présent) est placé en fin de déclaration de méthode pour indiquer que cette dernière peut lever une ou plusieurs exceptions en cas d’exécution anormale.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 | public void MaMethode() throws IndexOutOfBoundsException, IOException, NullPointerException { [...] } |
Ici, la signature de la méthode MaMethode() indique que cette dernière peut générer des exceptions de type IndexOutOfBoundsException, IOException et NullPointerException. Il s'agit d'une indication que tout code appelant cette méthode doit se préparer à gérer ces exceptions en cas d'erreur d’exécution de la méthode. Certaines déclarations et certains traitements sont obligatoires en fonction du type de l'exception générée.
Le mot-clé try (« essaie ») permet d'ouvrir un bloc contenant des instructions pouvant générer une ou plusieurs exceptions lorsque des erreurs surviennent. Généralement (mais pas toujours), un bloc try est suivi par un ou plusieurs blocs catch et parfois par un bloc finally.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 | try { [...] // Opération pouvant générer une exception. } |
Dans les JDK les plus récents, un bloc try permet également de s'assurer de la fermeture automatique de certaines ressources (fichier, flux, socket, etc.) ce qui évite de devoir les gérer manuellement.
Le mot-clé catch (« attrape ») permet d'ouvrir un bloc contenant des instructions servant à traiter une ou plusieurs exceptions. Ces blocs ne peuvent être positionnés qu’après un bloc try.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 | try { [...] // Opération pouvant générer une exception. } catch (MonException ex) { [...] // Traitement de l'erreur. } |
Plusieurs blocs catch peuvent être positionnés les uns après les autres pour gérer différents types d'exceptions et il est également possible, dans les JDK les plus récents, de capturer plusieurs types d'exceptions dans un même bloc catch
Le mot-clé finally (« enfin », « finalement ») permet d'ouvrir un bloc d'instructions qui sera tout le temps exécuté qu'il y ait une levée d'erreurs ou pas dans le bloc try ou les blocs catch qui le précèdent. Ce bloc ne peut être positionnés après un bloc try sans bloc catch ou après le dernier bloc catch qui suit un bloc try.
Par exemple :
Code Java : | Sélectionner tout |
1 2 3 4 5 | try { [...] // Opération pouvant générer une exception. } finally { [...] // Bloc d'instructions tout le temps exécuté qu'il y ait des erreurs ou pas dans le try. } |
Ou :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 | try { [...] // Opération pouvant lever une exception. } catch (MonException ex) { [...] // Traitement de l'erreur. } finally { [...] // Bloc d'instructions tout le temps exécuté qu'il y ait des erreurs ou pas dans le try ou le catch. } |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.