II. Variables et opérateurs▲
Ce chapitre décrit comment écrire des traitements en utilisant des variables, permettant de stocker des valeurs telles des nombres ou des mots et des opérateurs, représentant des symboles pour effectuer des calculs. Nous expliquerons également trois types d’erreurs de programmation puis nous vous donnerons des conseils additionnels pour les opérations de débogage des programmes.
II-A. Déclaration des variables▲
L’une des fonctionnalités les plus puissantes d'un langage de programmation est la possibilité de manipuler des variables. Une variable est un nom qui fait référence à une valeur. Les valeurs peuvent être des nombres, du texte, des images, du son, voire d’autres types de données. Afin de stocker une valeur, vous devez au préalable déclarer une variable.
String message;
Ce traitement est une déclaration, parce qu’il déclare que la variable nommée message est de type String. Chaque variable a un type déterminant quel genre de valeurs elle peut stocker. Par exemple, le type int permet de stocker des entiers, et le type char quant à lui permet de stocker des caractères.
Certains types débutent avec une majuscule et certains avec des minuscules. Nous apprendrons la signification de cette distinction plus loin dans cet ouvrage, mais pour l’instant, vous devez juste faire attention à cela. Sachez toutefois qu’il n’y a pas de type Int ni de type string.
Pour déclarer une variable de type entier nommée x, vous saisissez tout simplement
int
x;
Notez que x est un nom arbitrairement donné à cette variable. Les programmeurs choisissent généralement des noms significatifs pour leurs variables, qui expliquent à quoi sert la variable. Par exemple, en voyant la déclaration de ces variables, vous pouvez probablement en déduire les valeurs qu’elles devraient stocker :
2.
3.
String firstName;
String lastName;
int
hour, minute;
Cet exemple déclare deux variables avec le type String et deux avec le type int. Quand le nom d’une variable contient plus d’un mot, comme firstName, il est d’usage dans la convention des langages de programmation de mettre en majuscule la première lettre de chaque mot hormis la première.
Le nom des variables est sensible à la casse (minuscule ou majuscule) des lettres, donc firstName est différent de firstname ou de FirstName.
Cet exemple démontre également la syntaxe pour effectuer une déclaration multiple de variables du même type sur la même ligne : hour et minute sont toutes deux de type entier. Notez que chaque traitement de déclaration se termine par un point-virgule.
Vous pouvez utiliser n’importe quel nom pour une variable comme bon vous semble. Mais vous devez toutefois savoir que cinquante mots sont réservés par le langage Java, ils sont appelés mots-clefs ou mots réservés, vous n’êtes pas autorisé à les utiliser en tant que noms de variables.
Ces mots incluent public, static, void, et int, qui sont utilisés par le compilateur pour analyser la structure du programme.
Vous pouvez trouver la liste complète des mots-clefs à l’adresse suivante http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html, mais rassurez-vous, vous n’aurez pas à les retenir. La plupart des éditeurs de code possèdent « le surlignage syntaxique » faisant apparaître certaines portions de votre code, et notamment les mots réservés, d’une couleur différente.
II-B. Assignation▲
Maintenant que nous avons déclaré nos variables, nous voulons les utiliser pour stocker des valeurs. Nous effectuons cette opération avec un traitement d’assignation.
2.
3.
message =
"Hello!"
; // donner à message la valeur "Hello!"
hour =
11
; // assigner la valeur 11 à hour
minute =
59
; // initialiser minute à 59
Cet exemple nous montre trois assignations, et les commentaires associés illustrent les différentes façons dont les gens parlent parfois des déclarations d'affectation.
Le vocabulaire peut paraître confus à cet instant, mais le concept est simple :
- lorsque vous déclarez une variable, vous créez un espace de stockage nommé pour cette variable ;
- tandis que lorsque vous faites une assignation, vous mettez à jour la valeur de la variable.
En règle générale, une variable doit avoir le même type que la valeur à laquelle vous l’assignez. Par exemple, message peut contenir la chaîne de caractères "123", qui est composée des caractères '1', '2', et '3'. Ce qui est différent de l’entier 123.
message =
"123"
; // correct
message =
123
; // incorrect
Les variables doivent impérativement être initialisées (assignation d’une valeur) avant leur première utilisation. Vous pouvez déclarer une variable puis lui assigner une valeur par la suite, comme dans l’exemple précédent. Vous pouvez aussi effectuer l’opération de déclaration et d’affectation sur la même ligne.
2.
3.
String message =
"Hello!"
;
int
hour =
11
;
int
minute =
59
;
II-C. Diagramme d’état▲
Puisque le langage Java utilise le symbole = pour l’affectation, nous pourrions penser que le traitement a = b est interprété comme une égalité. Or ce n’est pas le cas !
L’égalité est commutative, alors que l’assignation ne l’est pas. Par exemple, dans le monde des mathématiques si a = 7 alors 7 = a.
Tandis que dans le monde Java a = 7 ; est une instruction d’assignation tout à fait correcte ; mais 7 = a ne l’est pas. L’opérande de gauche du traitement d’assignation doit absolument être le nom d’une variable (espace de stockage en mémoire).
Par ailleurs en mathématique, un traitement d’égalité est toujours vrai quoi qu’il en soit. Si a = b maintenant, a sera toujours égal à b. Tandis qu’en Java, un traitement d’assignation peut rendre deux variables égales à un point de l’exécution, mais elles n’ont pas à demeurer égales tout au long du programme.
int
a =
5
;
int
b =
a; // a et b sont maintenant égales
a =
3
; // a et b ne sont désormais plus égales
La troisième ligne modifie la valeur de a, mais ne modifie en aucun cas la valeur de b, donc les deux variables a et b ne sont désormais plus égales.
Prises ensemble, les variables d’un programme et leur valeur actuelle nous donnent l’état du programme. La figure 2.1 montre l’état du programme à l’issue des traitements d’assignation en cours.
Des diagrammes comme celui-ci montrant l’état du programme sont appelés des diagrammes d’état. Chaque variable est représentée dans une case affichant le nom de la variable dans le programme ainsi que sa valeur stockée en mémoire. Lors de l’exécution du programme, l’état change, donc vous devez garder à l’esprit que le diagramme d’état n’est qu’une image à l’instant t du programme et non son état définitif.
II-D. Affichage des variables▲
Vous pouvez afficher la valeur d’une variable en utilisant l’instruction print ou println. Les traitements suivants déclarent une variable nommée firstLine, lui assignent la valeur "Hello, again!", et affichent cette valeur.
String firstLine =
"Hello, again !"
;
System.out.println
(
firstLine);
Lorsque nous discutons d’affichage d’une variable, nous voulons dire par là la valeur de la variable et non son nom. Pour afficher le nom de la variable , nous devons placer son nom entre guillemets.
System.out.print
(
"La valeur de firstLine est "
);
System.out.println
(
firstLine);
Pour cet exemple nous avons l’affichage suivant :
La valeur de firstLine est Hello, again!
Comme par hasard, la syntaxe pour afficher une variable est totalement indépendante de son type. Par exemple :
2.
3.
4.
5.
6.
7.
int
hour =
11
;
int
minute =
59
;
System.out.print
(
"L’heure courante est "
);
System.out.print
(
hour);
System.out.print
(
" :"
);
System.out.print
(
minute);
System.out.println
(
"."
);
La sortie de ce programme est la suivante :
L’heure courante est 11
: 59.
Pour afficher plusieurs valeurs sur une seule et même ligne, il est d’usage d’utiliser plusieurs instructions print suivies d’une instruction println à la fin. Mais n’oubliez pas le println !
Sur certains systèmes, la sortie de l’instruction print est stockée sans pour autant être affichée tant que l’instruction println n’est pas saisie explicitement ; une fois l’instruction println saisie l’intégralité de la ligne est affichée.
Si vous omettez l’instruction println, il se peut que l’affichage du programme survienne à un moment inattendu, voire qu’il n’y ait pas d’affichage alors que le programme s’est terminé correctement.
II-E. Opérateurs arithmétiques▲
Les opérateurs sont des symboles représentant de simples opérations. Par exemple, l’opérateur pour l’addition est +, la soustraction -, la multiplication * et la division est /.
Le programme suivant convertit un temps donné en heures et minutes en minutes :
int
hour =
11
;
int
minute =
59
;
System.out.print
(
"Nombre de minutes depuis minuit : "
);
System.out.println
(
hour *
60
+
minute) ;
Dans ce programme, hour * 60 + minute est une expression représentant une simple valeur à calculer. Quand le programme s’exécute, chaque variable est remplacée par sa valeur courante, puis les opérations sont appliquées. Les valeurs des opérateurs travaillent sur les opérandes appelés.
Le résultat de l’exemple précédent est le suivant :
Le nombre de minutes depuis minuit : 719
Les expressions sont généralement la combinaison de nombres, de variables et d’opérateurs. Lors de la phase de compilation puis de l’exécution, elles deviennent une simple valeur.
Par exemple, l’expression 1 + 1 a pour valeur 2. Dans l’expression hour – 1, Java remplace la variable par sa valeur associée rendant ainsi 11 – 1, qui a pour valeur 10. Dans l’expression hour * 60 + minute, les deux variables sont remplacées par leurs valeurs respectives rendant derechef 11 * 60 + 59. La multiplication s’effectue en premier, rendant 660 + 59. Puis l’addition renvoie 719.
L’addition, la soustraction et la multiplication font chacune ce que l’on attend d’elles, mais vous risquez d’être surpris par la division. Par exemple, l’extrait de code suivant essaye de calculer la fraction d’une heure qui s’est écoulée :
System.out.print
(
"Fraction d’une heure écoulée : "
);
System.out.println
(
minute /
60
);
La sortie restituée est la suivante :
Fraction d’une heure écoulée : 0
Ce résultat peut paraître confus pour certaines personnes. La valeur de minute est 59, et 59 divisés par 60 devrait valoir 0,98333 et non pas 0. Le « problème » vient du fait que Java effectue une division euclidienne (sur des types entiers) lorsque les opérandes sont des entiers.
Intentionnellement, la division des nombres entiers est toujours arrondie à l’entier inférieur le plus proche, même dans des cas comme celui-ci où le résultat réel est plus proche d’un entier supérieur (ce n’est pas un arrondi automatique, mais une suppression de la partie décimale).
Comme autre possibilité, nous pouvons calculer un pourcentage plutôt qu’une fraction :
System.out.print
(
"Pourcentage de l’heure écoulée : "
);
System.out.println
(
minute *
100
/
60
);
La nouvelle sortie est la suivante :
Pourcentage de l’heure écoulée : 98
De nouveau le résultat est arrondi à la baisse, mais au moins maintenant il est approximativement correct.
II-F. Nombres à virgule flottante▲
Une solution plus générale consiste en l’utilisation des nombres à virgule flottante, qui peuvent représenter aussi bien des fractions (nombres réels) que des nombres entiers. En Java, le type par défaut pour les nombres flottants est appelé double, qui est le type court pour la double précision des nombres. Vous pouvez créer des variables de type double et leur assigner des valeurs en utilisant la même syntaxe utilisée que pour les autres types vus plus haut dans ce chapitre :
double
pi;
pi =
3.14159
;
Java effectue la « division des nombres à virgule flottante » quand un ou plusieurs opérandes sont des valeurs de type double. Ainsi nous pouvons résoudre le problème évoqué dans la section précédente :
double
minute =
59.0
;
System.out.print
(
"Fraction d’une heure écoulée : "
);
System.out.println
(
minute /
60.0
);
La sortie est :
Fraction d’une heure écoulée : 0.9833333333333333
Bien que les nombres à virgule flottante soient particulièrement utiles, ils peuvent devenir une source de confusion.
Par exemple, Java fait la distinction entre le nombre entier 1 et le nombre à virgule flottante 1,0. Bien qu’ils semblent représenter le même nombre, en réalité ils ne sont pas identiques.
Ce qu’il faut bien retenir c’est qu’ils appartiennent tous deux à des types de données différents, en d’autres termes, vous n’êtes pas autorisé à effectuer des comparaisons entre ces deux types distincts. L’expression suivante est illégale puisque la variable de gauche est un type entier alors que la valeur assignée à cette variable est un double :
int
x =
1.1
; // erreur de compilation
Il est facile d’oublier cette règle, car dans certains cas Java convertit automatiquement un type vers un autre :
double
y =
1
; // correct, mais mauvais style de programmation
L’exemple précédent devrait être illégal, mais Java permet cette écriture en convertissant la valeur 1 de type int en la valeur 1.0 de type double automatiquement.
Cette indulgence syntaxique est pratique, mais elle est souvent cause de problèmes pour les débutants en programmation. Par exemple :
double
y =
1
/
3
; // erreur courante
Il se peut que vous vous attendiez à ce que la variable y contienne la valeur 0,333333, qui correspond à la valeur d’un flottant. Mais au lieu de cela, la valeur est 0,0.
L’expression de droite divise deux entiers, donc Java effectue une division entière, qui renvoie donc la valeur de type int 0. Convertie en double, la valeur assignée à y est 0,0. Une méthode pour résoudre ce problème (une fois détecté comme n’étant pas un bug) est de transformer l’opérande de droite en flottant. Cette modification aura pour effet d’initialiser y à 0,333333, comme attendu :
double
y =
1.0
/
3.0
; // correct
En matière de style de programmation, vous devriez toujours assigner une valeur flottante à une variable à virgule flottante. Le compilateur ne vous demandera pas de le faire, mais vous devez être attentif aux différents types que vous manipulez. En adoptant un mauvais style, vous favorisez beaucoup l’apparition de bugs pas forcément évidents.
II-G. Erreurs d’arrondis▲
La plupart des nombres à virgule flottante ne sont qu’approximativement corrects. Certains nombres semblent être des décimaux bien définis dotés d’une précision infinie, cependant, en utilisant des variables contenant des fractions, comme 1.0/3.0 et des nombres irrationnels, comme π, nous nous rendons compte qu’ils ne le sont pas vraiment.
La différence entre le nombre que nous voulons réellement obtenir et le nombre que nous obtenons est appelée une erreur d’arrondi. Par exemple, les deux traitements suivants devraient être équivalents :
System.out.println
(
0.1
*
10
);
System.out.println
(
0.1
+
0.1
+
0.1
+
0.1
+
0.1
+
0.1
+
0.1
+
0.1
+
0.1
+
0.1
);
Mais sur certaines stations de travail, la sortie est :
1.0
0.9999999999999999
Le problème est que la valeur 0,1 est une fraction décimale terminale, en quelque sorte une fraction répétitive en nombre binaire. Ce qui entraîne que cette représentation de ce nombre flottant n’est qu’approximative.
Lorsque nous ajoutons des approximations dans nos calculs, les erreurs d’arrondi s’accumulent. Dans plusieurs types d’applications, telles les applications utilisant des calculs graphiques, de la cryptologie, des analyses statistiques ou du rendu multimédia, l’arithmétique avec les flottants a le bénéfice d’alléger les coûts. Cependant, si vous avez besoin d’une absolue précision, nous vous recommandons vivement d’utiliser des entiers. Par exemple, considérons un compte bancaire ayant le solde de 123,45€ :
double
balance =
123.45
// erreur potentielle d’arrondi
Dans cet exemple, au fur et à mesure des opérations arithmétiques de retraits et de versements ,la valeur de la variable balance deviendra inexacte. Le résultat risque d’énerver les clients et d’entraîner des poursuites judiciaires à l’encontre de la banque. Vous pouvez toutefois éviter cet inconvénient en typant la variable balance en un nombre entier.
int
balance =
12345
// totaliser le nombre en centimes
Cette solution fonctionne tant que le nombre totalisé n’excède pas la taille limite d’un nombre de type entier, c’est-à-dire proche des 2 milliards.
II-H. Opérateurs pour les chaînes de caractères▲
En règle générale, vous ne pouvez pas effectuer d’opérations mathématiques sur les chaînes de caractères, et ce même si la chaîne ressemble à un nombre. Les expressions suivantes sont illégales :
"Hello"
-
1
"World"
/
123
"Hello"
*
"World"
L’opérateur + fonctionne avec les chaînes de caractères, toutefois le résultat renvoyé n’est pas toujours celui espéré. Pour les chaînes de caractères, l’opérateur + permet la concaténation, opération qui permet la jointure bout à bout des chaînes de caractères concernées. Ainsi :
"Hello, "
+
"World !"
renvoie la chaîne de caractère "Hello, World !"
.
Ou, si vous avez une variable nommée name de type String, l’expression "Hello, "
+
name attache la valeur de la variable name à la chaîne de caractères hello, qui crée par la suite une chaîne d’invite personnalisée. Dès lors qu’une opération d’addition est définie entre des nombres et une chaîne de caractères, Java effectue automatiquement une conversion à laquelle vous ne vous attendiez probablement pas :
2.
3.
4.
System.out.println
(
1
+
2
+
"Hello"
);
// la sortie est 3Hello
System.out.println
(
"Hello"
+
1
+
2
) ;
// la sortie est Hello12
Java exécute les opérations de la gauche vers la droite. La première ligne, 1 + 2 donne 3, et 3 + "Hello" donne "3Hello".
Quand plus d’un opérateur apparaît dans une expression, chacun est évalué selon l’ordre de précédence des opérateurs. En général, Java évalue les opérateurs de la gauche vers la droite (comme nous l’avons vu dans la section précédente). Mais dès lors qu’il s’agit des opérateurs arithmétiques, Java suit les règles des conventions mathématiques :
- la multiplication et la division sont prioritaires sur l’addition et la soustraction, ce qui signifie que la multiplication et la division sont effectuées en premier puis viennent l’addition et la soustraction. Donc 1 + 2 * 3 renvoie 7 et non 9, et 2 + 4 / 2 renvoie 4 et non 3 ;
- si les opérateurs ont la même précédence, ils sont évalués de la gauche vers la droite. Ainsi dans l’expression minute * 100 / 60, la multiplication s’effectue en premier ; si la valeur de minute vaut 59, nous obtenons 5900 / 60, qui nous renvoie 98. Si ces mêmes opérations étaient effectuées de la droite vers la gauche, le résultat aurait été 59 * 1, qui est incorrect ;
- si toutefois vous voulez modifier l’ordre de précédence des opérateurs (ou si vous n’êtes pas sûr de ce qu’il en ressort) vous pouvez utiliser des parenthèses. Dès lors, les expressions mises entre parenthèses sont évaluées en premier, ainsi (1 + 2) * 3 donne 9. Vous pouvez également utiliser des parenthèses pour rendre une expression plus facile à lire, comme dans l’expression (minute * 100) / 60, même si cela ne changera pas le résultat final.
Ne vous cassez pas la tête à mémoriser l’ordre de précédence des opérateurs, notamment pour les autres opérateurs non listés ici. Si vous avez un doute sur le résultat en regardant une expression, utilisez les parenthèses pour rendre les choses plus claires.
II-I. Composition▲
Nous avons vu les différents éléments du langage de programmation – les variables, les expressions et les traitements – de façon isolée, sans se soucier de leur imbrication. L’une des fonctionnalités les plus utilisées des langages de programmation et qui correspondent à leur aptitude primordiale est de construire des petits blocs et de les associer. Par exemple, nous savons comment multiplier des nombres et nous savons comment afficher ces valeurs. Nous pouvons dès lors combiner ces opérations dans un unique traitement :
System.out.println
(
17
*
3
);
N’importe quelle opération arithmétique peut être utilisée à l’intérieur d’une instruction print. Nous avons déjà vu un exemple comme celui-ci :
System.out.println
(
hour *
60
+
minute);
Vous pouvez aussi placer arbitrairement des expressions dans l’opérande de droite de l’assignation :
int
percentage;
percentage =
(
minute *
100
) /
60
;
L’opérande de gauche de l’assignation doit être un nom de variable et non une expression. Tout simplement par le fait que l’opérande de gauche décrit où sera stocké le résultat de l’expression, et bien entendu une expression ne peut pas représenter un espace de stockage en mémoire.
hour =
minute +
1
; // correct
minute +
1
=
hour; // incorrect → erreur de compilation
L’aptitude à composer des expressions ne vous semble peut-être pas impressionnante pour l’instant, mais nous verrons par la suite des exemples plus complexes de calcul nous autorisant à écrire des expressions proprement et de façon concise.
Toutefois, ne vous laissez pas emporter. Les expressions complexes et volumineuses peuvent être difficiles à lire et à déboguer.
II-J. Types d’erreurs rencontrés▲
Trois types d’erreurs peuvent apparaître dans un programme : des erreurs survenant lors de la compilation du programme, lors de l’exécution du programme ou tout simplement des erreurs de logique dans l’écriture du programme. Il est primordial de les distinguer afin de les traquer rapidement. Les erreurs lors de la compilation apparaissent lorsque vous ne respectez pas les règles syntaxiques du langage Java. Par exemple, les parenthèses et les accolades vont de pair. Ainsi (1 + 2) est légal, mais 8) ne l’est pas. Dans le dernier cas, le programme ne compileras pas, et le compilateur affichera une erreur. Les messages d’erreur du compilateur indiquent d’habitude où dans le programme l’erreur est apparue, et parfois, peuvent même vous indiquer exactement quelle est la cause de l’erreur. Comme exemple, retournons dans le programme hello world de la Section 1.4
2.
3.
4.
5.
6.
7.
public
class
Hello {
public
static
void
main
(
String[] args) {
// génère une simple sortie
System.out.println
(
"Hello World !"
) ;
}
}
Si vous oubliez le point-virgule à la fin de l’instruction print, il se peut que vous ayez un message d’erreur comme celui-ci :
File
:
Hello.java [line: 5
]
Error
:
';'
expected
Ce qui est une bonne chose en soi : la localisation de l’erreur est correcte, et le message d’erreur vous dit ce qui ne va pas. Mais sachez toutefois que tous les messages d’erreur ne sont pas aussi faciles à comprendre. Parfois le compilateur rapporte l’endroit dans le programme où l’erreur a été détectée, mais pas l’erreur en elle-même où elle est présente dans le programme. Et parfois même la description du problème est plus confuse que toute autre chose.
Par exemple, si vous laissez une accolade ouverte à la fin du main (ligne 6), vous obtiendrez probablement le message d’erreur suivant :
File
:
Hello.java [line: 7
]
Error
:
reached end of file while
parsing
Il y a deux problèmes ici. Premièrement, le message d’erreur est écrit du point de vue du compilateur et non du vôtre. Parsing représente le processus de lecture d’un programme avant la traduction par le compilateur ; si le compilateur obtient l’indicateur de fin du fichier alors qu’il est encore en train de parser le fichier c’est qu’il y a un problème quelque part et que quelque chose a été omis. Mais le compilateur ne sait pas de quoi il s’agit. Et surtout ne sait pas où cela se situe dans le programme. Le compilateur découvre l’erreur à la fin du programme (ligne 7), mais l’accolade manquante devrait être sur la ligne précédente.
Les messages d’erreur contiennent des informations utiles, donc vous devriez faire un effort pour les lire et essayer de les comprendre. Mais ne les prenez pas toujours au pied de la lettre. Durant les quelques premières semaines de votre carrière de programmeurs, vous passerez probablement beaucoup de temps à traquer les erreurs de compilation. Cependant, lorsque vous gagnerez de l’expérience, vous ferez moins d’erreurs et les trouverez plus rapidement qu’à vos débuts.
Le second type d’erreur est constitué par les erreurs d’exécution du programme, appelées ainsi parce qu’elles ne peuvent apparaître que lorsque le programme est en cours d’exécution. En Java, ces erreurs apparaissent lorsque l’interpréteur est en train d’exécuter du byte code et que quelque chose s’est mal déroulé. Ces erreurs sont également appelées des « exceptions » parce qu’elles indiquent d’habitude que quelque chose d’exceptionnel (et de « mal ») est arrivé.
Les erreurs d’exécution sont rares dans des programmes simples vous le verrez dans les tout premiers chapitres de ce livre, donc il est possible qu’il s’écoule un peu de temps avant que vous en trouviez une. Quand une erreur d’exécution apparaît, l’interpréteur affiche un message d’erreur expliquant ce qui arrive et où cela arrive. Par exemple, si vous effectuez accidentellement une division par zéro, vous aurez probablement un message d’erreur tel que celui-ci :
Exception in thread "main"
java.lang.ArithmeticException: /
by zero
at Hello.main
(
Hello.java:5
)
Le débogage s’avère dès lors facile à effectuer. La première ligne reprend le nom de l’exception, java.lang.ArithmeticException, et un message indiquant précisément ce qui est arrivé, / by zero. La ligne suivante montre la méthode où l’erreur est survenue ; Hello.main indique la méthode main dans la classe Hello. Le fichier où la méthode est définie, Hello.java est également mentionné ainsi que le numéro de la ligne où l’erreur est apparue, ici la ligne 5.
Les messages d’erreur contiennent parfois des informations additionnelles qui n’ont pas encore de sens pour vous. Ainsi, l’un des défis réside dans la capacité à savoir où trouver l’information utile sans être submergé par le superflu. Gardez donc toujours à l’esprit que la ligne où le programme « crash » n’est pas forcément la ligne qui nécessite une correction.
Le troisième type d’erreur est constitué par les erreurs de logique dans l’élaboration du code de votre programme. Si votre code contient une erreur de logique, le programme se compilera et s’exécutera sans générer aucun message d’erreur, mais il ne fera pas ce que vous espériez qu’il fasse lors de sa conception. Au lieu de cela, il fera exactement ce que vous lui avez dit de faire stricto sensu. Par exemple, voici une version du programme hello world avec une erreur de logique :
2.
3.
4.
5.
6.
7.
public
class
Hello {
public
static
void
main
(
String[] args) {
System.out.println
(
"Hello, "
) ;
System.out.println
(
"World !"
) ;
}
}
Ce programme compilera et s’exécutera comme il le faut, mais la sortie affichera ceci :
Hello,
World !
En partant sur le principe que nous aurions souhaité avoir l’affichage sur une seule et même ligne, le résultat est donc incorrect. Le problème réside dans le fait que la première ligne utilise println, alors que nous aurions dû utiliser print (voir l’exemple du programme « goodbye world » de la Section 1.5). L’identification des sources d’erreurs est extrêmement compliquée à faire parce que vous devez revenir en arrière dans la conception de votre code, explorer la sortie de votre programme, essayer de trouver pourquoi quelque chose d’« inattendu » apparaît alors que tout vous semble correct, et surtout trouver comment faire pour que tout fonctionne comme vous le souhaitez. Dans ce type de situation, l’interpréteur et le compilateur ne vous seront d’aucun soutien, tout simplement parce qu’ils ne savent pas de quoi il en ressort et quel est le résultat attendu.
Maintenant que vous connaissez ces trois types d’erreurs, vous voudrez probablement lire l’ Annexe C, où nous avons collecté quelques-uns de nos conseils préférés pour le débogage. Il fait référence aux fonctionnalités du langage que nous n’avons pas évoqué jusque là, donc vous aurez probablement à les relire de temps en temps.
II-K. Vocabulaire▲
variable : espace de stockage nommé pour contenir des valeurs. Toutes les variables sont typées, le type est défini dès la déclaration de la variable.
valeur : nombre, une chaîne de caractères ou un autre type de données pouvant être stocké dans une variable. Toutes, absolument toutes les valeurs appartiennent à un type (par exemple, int ou String).
déclaration : traitement créant une nouvelle variable et spécifiant son type.
type : du point de vue mathématique, il s’agit d’un ensemble de valeurs. Le type d’une variable détermine quelles sont les valeurs qu’il peut accepter.
syntaxe : disposition des mots et des symboles propres au langage.
mot-clef : mot réservé utilisé par le compilateur pour analyser les programmes. Vous ne pouvez pas utiliser des mots-clefs (comme public, class, et void) comme noms de variables.
assignation : instruction donnant une valeur à une variable.
initialiser : assigner une variable pour la première fois.
état : variables dans le programme et leur valeur courante.
diagramme d’état : représentation graphique de l’état d’un programme à un moment donné.
opérateur : symbole représentant un calcul arithmétique comme une addition, une multiplication ou la concaténation d’une chaîne de caractères.
opérande : une des valeurs sur lesquelles porte un opérateur. La plupart des opérateurs en Java nécessitent deux opérandes.
expression : combinaison de variables, opérateurs et valeurs représentant une valeur unique. Les expressions ont également des types, déterminés par leurs opérateurs et leurs opérandes.
nombre à virgule flottante : type de données représentant des nombres avec une partie entière et une partie fractionnaire. En Java, double est le type par défaut pour les nombres à virgule flottante.
erreur d’arrondi : différence entre le nombre que nous voulons représenter et le nombre flottant le plus proche.
concaténer : opération permettant de joindre bout à bout deux valeurs, le plus souvent des chaînes de caractères.
ordre des opérations : règles déterminant dans quel ordre les opérations sont évaluées.
composition : aptitude de combiner des expressions simples et des traitements à l’intérieur d’un traitement et d’une expression composée.
erreur de compilation : erreur survenant dans le code source rendant impossible la compilation du programme. Aussi connue sous le nom d’erreur de syntaxe.
parser : opération permettant d’analyser la structure d’un programme ; ce que le compilateur doit faire en premier.
erreur d’exécution : erreur survenant dans le programme rendant impossible l’exécution complète de ce dernier. Aussi connue sous le nom d’ « exception».
erreur de logique : Une erreur survenant dans le programme entraînant un comportement différent du programme de ce qui est attendu par le programmeur.
II-L. Exercices▲
Le code source de ce chapitre est présent dans le répertoire ch02 de ThinkJavaCode.
Référez-vous à la page xv concernant les instructions pour le téléchargement du répertoire. Avant de commencer les exercices, nous vous recommandons de compiler et d’exécuter les différents exemples.
Si vous n’avez pas encore lu l’Annexe A.2, ce serait une bonne chose de le faire maintenant. Cette annexe décrit le panneau des interactions de l’éditeur DrJava, qui représente un bon compromis pour tester de courts fragments de code sans pour autant écrire une définition complète de classe.
Exercice 2.1. Si vous utilisez ce livre dans une classe d’école, vous serez ravi de faire cet exercice. Trouvez un partenaire et jouez à « Stump the Chump » :
Commencez le programme en le compilant et en l’exécutant sans erreur. L’un d’entre vous s’éloigne alors que l’autre ajoute une erreur dans le programme. Celui qui s’est éloigné tente de trouver la cause du problème puis de corriger cette dernière. Vous gagnez deux points si vous trouvez la cause du problème sans passer par la phase de compilation, un point si vous trouvez la cause à l’aide du compilateur, tandis que votre collègue gagne un point si vous ne trouvez pas la cause de l’erreur.
Exercice 2.2. Le but de cet exercice est (1) d’utiliser la concaténation des chaînes de caractères pour afficher des valeurs de différents types (int et String) et à la fois (2) de pratiquer le développement de programmes en ajoutant progressivement quelques traitements.
- Créez un nouveau programme que vous appellerez Date.java. Copiez ou tapez quelque chose comme le programme hello world et assurez-vous que vous pouvez compiler et exécuter ce programme.
- Suivant l’exemple de la Section 2.4, écrivez un programme qui crée une variable nommée jour, date, mois et annee. La variable jour contiendra le jour de la semaine (exemple vendredi), et la date contiendra le jour du mois (exemple le 13). Quel est le type de chaque variable ? Assignez des valeurs à ces variables représentant la date d’aujourd’hui.
- Affichez (sur l’écran) la valeur de chaque variable. Chaque variable doit être affichée toute seule sur une ligne. Il s’agit d’une étape intermédiaire pour vérifier que tout fonctionne correctement jusque là. Compilez et exécutez votre programme avant d’aller de l’avant.
- Modifiez le programme afin qu’il affiche la date au format standard américain, par exemple : Jeudi, juillet 26, 2018.
- Modifiez le programme afin qu’il affiche la date au format standard européen. La sortie finale devrait ressembler à ceci :
American format:
jeudi, juillet 26
, 2018
European format:
jeudi 26
juillet 2018
Exercice 2.3. Le but de cet exercice est (1) d’utiliser des opérateurs arithmétiques, et (2) de commencer à réfléchir sur l’utilisation des entités composées (comme l’heure du jour) qui consistent à associer de multiples valeurs.
- Créez un nouveau programme que vous appellerez Time.java. À partir de maintenant vous devrez démarrer d’un programme vide (plus aucun copier-coller d’un autre programme existant).
- En suivant l’exemple de du programme de la Section 2.4, créez des variables nommées heure, minute et seconde. Assignez des valeurs en « dur » représentant l’heure actuelle. Utilisez une convention horaire 24h telle que 2 heures de l’après-midi représente la valeur 14 pour la variable heure.
- Faites en sorte que le programme puisse calculer et afficher le nombre de secondes depuis minuit.
- Calculez le nombre de secondes restantes jusqu’à la fin de la journée.
- Calculez et affichez le pourcentage de temps écoulé depuis le début de la journée. Il se peut que vous ayez des problèmes lors du calcul des pourcentages avec des nombres entiers, donc, il est préférable que vous utilisiez des nombres flottants.
- Modifiez les valeurs d’heure, minute et seconde pour refléter l’heure actuelle. Puis écrivez le code permettant de calculer le temps écoulé depuis que vous avez commencé à travailler sur cet exercice.
Conseil : il se peut que vous ayez besoin d’utiliser des variables additionnelles pour effectuer vos calculs. Ces variables utilisées pour les calculs, mais qui ne sont jamais affichées sont appelées des variables « intermédiaires » ou « temporaires ».