Java/Annexe/Oral de java
Cette page reprend les mots-clés 2013 du cours LGJ de langage JAVA au sein de l'ESI.
Considérez ces fiches comme des résumés plus ou moins exhaustifs des notions auxquelles elles font référence. Elles ont pour but d'affiner la compréhension de l'emploi des dites notions lorsque l’on fait usage du langage JAVA pour coder.
Des liens plus complets pour chaque mots-clés seront ajoutés.
Toute aide est la bienvenue.
autoboxing
modifierCas d’usage
modifierLe boxing est le processus de conversion d'un type primitif en type objet. L'inverse du boxing est l'unboxing (objet vers primitif). À chaque type primitif correspond une classe englobante (wrapper) :
type primitif | wrapper |
---|---|
boolean | Boolean |
byte | Byte |
char | Character |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
L'objet a la même valeur que la valeur primitive ; utile lorsqu'un objet est requis.
L'autoboxing est donc une conversion automatique d'un type primitif vers un wrapper (boxing), ou inversement, d'un wrapper vers un type primitif (unboxing). Cette conversion est ajoutée par le compilateur dans les expressions, dans les assignations et avec les paramètres effectifs.
Exemple de code
modifierList<Integer> list = new ArrayList<>();
list.add(1);
System.out.println(list.get(0) + 1);
list.set(0, list.get(0) + 1);
int i = list.get(0);
break/continue
modifiercas d’usage
modifierbreak
modifierbreak
est un arrêt inconditionnel de l'instruction. À l'instar du saut conditionnel, il est associé à une structure conditionnelle(boucle for, while), sans laquelle la boucle ne ferait jamais plus d'un tour.
for (int x=1; x<=10; x++) {
a = x-7;
if (a == 0) {
System.out.println("division par 0");
break;
}
System.out.println(1.0/a);
}
- Si pas d'étiquette → arrête la première instruction
while
/for
/do
/switch
englobante. - Si étiquette → arrête brutalement l'instruction étiquetée et passe à la suivante.
continue
modifiercontinue
est un saut inconditionnel. Associé a une structure conditionnelle, il permet de passer aux instructions suivantes sans mettre fin à la boucle, ou la suite d'instruction.
x=1;
for (int x=0; x<=10; x++) {
if (x == 7) {
System.out.println("Division par zéro!");
continue;
}
double a = 1.0/(x-7);
System.out.println(a);
}
- Si pas d'étiquette → recommence la première instruction répétitive englobante
- Si étiquette → recommence la boucle étiquetée
exemple de code
modifiercode=/* Exemple d'utilisation de while */
int nb;
while(true) {
nb = clavier.nextInt();
if (nb>0) break;
System.out.println("Mauvais nombre. Recommencer.");
}
/* Exemple d'utilisation de continue */
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue;
System.out.println(i);
}
constructeur
modifiercas d’usage
modifierUn constructeur est une méthode qui sert à créer une instance d'un objet. Il ne retourne rien et a le même nom que celui de la classe.
Il existe deux types de constructeurs :
- le constructeur par défaut, sans paramètre ;
- le constructeur avec un ou plusieurs paramètres, permettant d'attribuer directement les valeurs des paramètres aux attributs.
Il peut ne pas y avoir de constructeur explicite : rarement une bonne idée → toujours écrire explicitement un constructeur.
exemple de code
modifierpublic Etudiant (int unNuméro, String unNom) {
numéro = unNuméro;
nom = unNom;
annéeÉtude = 1;
doubleur = false;
ancien = false;
}
conversions
modifiercas d’usage
modifier(la partie qui suit n'a pas vraiment de structure, j’ai simplement rassemblé les informations trouvées dans le cours théorique)
On ne peut normalement pas mélanger des variables de types différents. Cela est cependant accepté s'il n'y a pas de perte d'information. La conversion est effectuée automatiquement par le compilateur.
Java étant un langage fortement typé, les types doivent correspondre entre eux. Lors d'un assignation par exemple, la valeur doit être du type de la variable. Il y a 8 sortes de sortes de conversions, qui peuvent être utilisées dans 5 contextes différents. Il existe des conversions implicites dans les expressions :
- Uniquement pour des expressions numériques
- Adapte le type des opérandes à ceux attendus par l’opérateur
- Conversion la plus fréquente : élargissante de type primitif
Conversion élargissante de type primitif (widening primitive conversion) :
- Vers un type plus général : byte → short → int (← char) → long → float → double
- Réel vers entier : perte de précision possible
Cas des opérandes binaires :
- Opérateurs : +, -, *, /, %, <, >, <=, >=, ==, !=
- Si opérandes de types différents : on élargit le moins large
- On élargit au minimum vers int (car les opérateurs n'existent pas en dessous)
Cas des opérateurs unaires :
- Opérateurs : +, -, ainsi que l'indice d'un tableau
- byte, short, char → int
Remarque sur ++ :
- Existe pour tous les types numériques
- Attention, sur un char par exemple :
a++
est différent dea ← a + 1
Que se passe-t-il lors d'une assignation ?
- Adapte le type de l’expression au type de la variable
- Opérateurs : =, +=, -=, *=, /=, %=
- Permet la conversion élargissante et arrondissante.
encapsulation
modifiercas d’usage
modifierL'encapsulation
est le concept d'accessibilité appliqué aux méthodes et aux classes. Elle permet au concepteur de restreindre ou non l'accès a certaines méthodes/classes. la visibilité est définie par les mots clés public
, private
et protected
.
L'encapsulation est associé au concept des mutateurs et des assesseurs. Pour permettre l'usage d'une méthode private
par des méthodes externes, ils sont indispensables.
L'encapsulation permet donc de protéger son code tout en prévoyant des outils pour en faire usage.
enum
modifiercas d’usage
modifierUne énumération est un ensemble fixe et petit de valeurs ayant un nom et étant sémantiquement liées.
Le mot-clé enum
:
- définit un nouveau type de données ;
- est au même niveau que
class
; - est défini dans un fichier à part ou au sein d'une autre classe.
On peut par exemple accéder aux différentes valeurs d'une classe enum
grâce à un switch
, une boucle for
, ou encore un foreach
.
On peut également y ajouter des attributs ou ses propres méthodes.
exemple de code
modifierpublic enum Saison {
PRINTEMPS, ÉTÉ, AUTOMNE, HIVER;
}
equals
modifiercas d’usage
modifierLa méthode equals
compare deux objets et renvoie un booléen selon que ceux-ci sont égaux (dans le même état) ou non.
La méthode par défaut dans Object
se contente de comparer les références (les objets sont des types références) → besoin de la réécrire :
- Il faut respecter la signature.
- La méthode doit renvoyer
false
si on compare à un autre type ou ànull
.
Elle est utilisée notamment dans les listes, dans les méthodes contains
, indexOf
, remove
, etc.
final
modifiercas d’usage
modifierLe mot-clé final en java peut s’utiliser de différentes façons; en générale il est là pour dire que la chose à laquelle il est lié ne peut pas changer.
- final pour variable : si on déclare une variable final, elle ne pourra pas changer de valeur. Tout le long de l’exécution du programme, cette variable gardera la valeur de son initialisation. Cette variable doit être primitive et doit être initialisée avec une valeur. Cette variable sera donc constante. Si on utilise final sur une référence, celle-ci ne pourra pas référencer un autre objet, la référence sera liée à l’objet. L’objet référencé peut par contre, changer de valeur.
Si on n’initialise pas une variable final, on est obligé de le faire avant d’utiliser cette variable.
- final pour un argument : cela veut dire que la méthode qui reçoit l’argument final ne pourra changer ce vers quoi il pointe.
- final pour méthode : permet que l’on ne puisse redéfinir la méthode. Une autre classe ne pourra donc pas la ré implémenté. Cela permet d’être certain que le comportement de cette méthode ne changera pas durant l’héritage (empêche la surcharge).
- final pour une classe: empêche de pouvoir hériter de cette classe. On peut choisir de rendre une classe final pour des raisons de sécurité. Cette classe ne pourra donc pas être modifiée.
exemple de code
modifierfinal int a = 9 ; // déclaration d'une variable final
a=10 ; // On ne pourra donc pas écrire ceci : cela produit une erreur de compilation.
maMéthode( final int b) { // utilisation d'argument final
b = 5 ; // ne compilera pas interdit !!!
return b ;
}
for
modifiercas d’usage
modifierLa boucle for
teste une condition et exécute les instructions qui la compose tant que cette condition n’est pas remplie. On l'utilise généralement pour parcourir des listes ou des tableaux.
Contrôles de la boucle en tête de boucle pour une meilleure lisibilité :
- l'initialisation
- l'évaluation du test
- si le test vaut
true
, alors :- le corps
- incrémentation (au sens large)
- retour à l'étape 2
- sinon, on passe à l'instruction suivant le
for
Utilisé en général quand le nombre d'itérations est connu.
exemple de code
modifierfor (int i = 0; i < 10; i++) {
System.out.println(i);
}
foreach
modifierÉcriture simplifiée du for
. Utile pour parcourir un tableau, une liste ou un enum
.
Attention ! On accède aux éléments mais pas à l'indice ! → OK pour consulter mais pas pour modifier.
for (String mot: dictionnaire){
System.out.println(mot);
}
I/O
modifiercas d’usage
modifierI/O désigne Input/Output ou Entrées/Sorties.
- Les Entrées sont l’ensemble des périphériques, fichiers, ou objets permettant de recevoir des données à la machine.
Exemple : Clavier, souris, tablette tactile, scanner de badge, fichier, objet, …
- Les Sorties sont l’ensemble des périphériques permettant de sauvegarder/afficher des données.
Exemple : Écran, imprimante, fichier, objet, …
L’entrée-sortie peut-être de type :
- binaire (byte) ou texte (char)
- séquentiel, direct, . . .
On peut y accéder en lecture, écriture, lecture/écriture, . . .
On peut l’envisager à partir de / vers un fichier mais aussi d’un tableau en mémoire, socket, autre application.
Les différent flux sont :
- Flux standard
- Flux binaire
- Flux de caractère (texte)
- Flux englobant
- Flux formaté
- Flux de type primitif
exemple de code
modifierpublic void sauver(String nomFichier) {
File saveFile = new File(nomFichier);
this.lastParties = new Stack<Partie>();
try {
FileOutputStream out = new FileOutputStream(saveFile);
ObjectOutputStream save = new ObjectOutputStream(out);
lastParties.push(puissance4); save.writeObject(lastParties);
save.close();
out.close();
} catch (IOException e) {
}
}
Voir aussi : java.io
i++/++i
modifiercas d’usage
modifier++
permet d'incrémenter une variable. Il peut se placer avant ou après la variable.
Il y a cependant une différence :
- pour
++i
,i
est incrémenté avant d’être utilisé :i
est incrémentéi
donne sa valeur à l’expression++i
- pour
i++
,i
est incrémenté après avoir été utilisé :i
donne sa valeur à l’expressioni++
i
est incrémenté
exemple de code
modifierint i = 5;
int a;
a = i++ + ++i; // 5 + 7
System.out.println("a vaut : "+a); // 12
System.out.println("i vaut : "+i); // 7
Détaillons a = i++ + ++i
si i = 5
:
- On est face à une assignation. Il faut donc évaluer l’expression à droite puis la donner à
a
. - L'expression à évaluer est une somme. Il faut donc évaluer les 2 opérandes
i++
et++i
. Dans quel ordre ? Java évalue toujours l'opérande de gauche PUIS celle de droite ; - Il faut donc évaluer
i++
. Cette expression a une valeur5
et on incrémentei
(qui vaut 6) mais l'évaluation est faite avant,i++
vaut donc5
; - On évalue à présent
++i
. D'abord on incrémente eti
passe à7
. On évalue alorsi
donc++i
vaut7
; - Les 2 opérandes étant évalués, on peut faire la somme du point 2 :
5 + 7 = 12
; - l’expression à droite de l'assignation vaut donc
12
, et on peut terminer le point 1 :a
reçoit12
; - On a donc bien
a = 12
eti = 7
.
Dis autrement:
- a = i++ + ++i
- a = ( (i++) + (++i) ) // pour montrer comment les priorités induisent les parenthèses
- a = ( (5) + (++i) ) // i est utilisé puis passe à 6
- a = ( (5) + (7) ) // i passe à 7 puis est utilisé
- a = 12.
if
modifiercas d’usage
modifierLe if
est associé à une condition. Si celle-ci est remplie, le code contenu dans le if
est exécuté, sinon on en sort et ce qui suit est exécuté. Il peut être suivi par une instruction, pas forcément un bloc.
Le if
peut être suivi d'un else
, ou encore d'un else if
.
exemple de code
modifierpublic static void afficheTableau(int[] tableau) {
if (tableau == null) {
throw new IllegalArgumentException("pas de tableau !");
}
if (tableau.length() > 0) {
System.out.println ("Contenu du tableau : ");
for (int i = 0; i < tableau.length(); i++) {
System.out.println("en "+ i + " : " + tableau[i]);
}
} else {
System.out.println("tableau vide");
}
}
implements
modifiercas d’usage
modifierimplements
permet d'implémenter une interface : définir toutes les méthodes d'une interface.
On déclare qu'on implémente l'interface. Le compilateur vérifie ensuite qu'on fournit bien le code de chaque méthode.
exemple de code
modifierpublic class MaClasse implements MonInterface {
public void maMéthode1(int a) {
// le corps de la méthode
}
public boolean maMéthode2(char c) {
// le corps de la méthode
}
// + d'autres méthodes si on veut
}
import
modifierPour utiliser une classe existante, on peut soit mettre le nom qualifié (complet), soit utiliser import
qui crée un raccourci.
Cas particulier : le package java.lang
est importé implicitement. On peut donc utiliser directement les classes qui le constituent.
import java.util.Calendar;
public Test {
// ...
Calendar now = Calendar.getInstance();
// ...
}
instanceof
modifierL'opérateur instanceof
permet de vérifier qu'un objet appartient à une classe donnée (ou un de ses enfants). Par définition, null
n'est instance de rien.
public boolean equals(Object o) {
if (!(o instanceof Etudiant)) {
return false;
}
// ...
}
instruction-expression
modifiercas d’usage
modifier- Une instruction représente les ordres donnés pour l’exécution du code, soit presque chaque ligne du code.
- Une instruction peut être :
- une affectation : x = 1 ;
- un ordre d'affichage : systemOut.println() ;
- une conditionnelle : if... else... ;
- une boucle : for... while... .
- Une expression est un ensemble de symbole représentant un calcul ayant une valeur et un type.
- Une expression peut être :
- une variable : x ;
- une expression arithmétique : 3/4 ;
- une expression booléenne : true ou x<10 ;
- une chaine de caractère ;
- un appel a une fonction : nomClass.nomMethod().
- Une instruction peut être une expression, et vice-versa. Si une expression n’est pas une instruction, alors elle ne s'utilise qu'au sein d'une instruction, et pas toute seule.
exemple de code
modifierx+3 ; // est une expression, cette instruction est donc fausse.
x = 3 + 5 ; // est une instruction-expression.
liste
modifiercas d’usage
modifierUne liste est une séquence d'éléments (ordonnés mais pas nécessairement triés) auxquels on accède via leur position.
Ce concept est présent en Java, pas dans le langage, mais via l'API standard : java.util.ArrayList<E>
ou java.util.LinkedList<E>
.
On spécifie le type des éléments (via les <>). Au départ, la liste est vide, mais elle pourra évidemment grandir au besoin (pas de limite). Le premier élément est en position 0 ; une insertion provoque un décalage des éléments suivants. Les éléments ne peuvent pas être de type primitif, on doit donc recourir à des wrappers (enveloppes). Quelques méthodes de l'interface List :
Informations sur l'état de la liste | |
---|---|
int size(); | Récupère le nombre d'éléments dans la liste |
boolean isEmpty(); | Permet de savoir si la liste est vide |
boolean contains (Object o); | Permet de savoir si la liste contient l’objet o |
Object get (int i); | Renvoie l’objet se trouvant à l'indice i |
Agir sur les éléments de la liste | |
---|---|
void add (Object o); | Ajoute l’objet o en fin de liste |
void add (int i, Object o); | Ajoute l’objet o à l'indice i |
void set (int i, Object o); | Remplace l’objet de l'indice i par l’objet o |
Object remove (int i); | Retire l’objet de l'indice i et le renvoie |
boolean remove (Object o); | Retire l’objet o de la liste et renvoie true ou false si l’objet n'existe pas dans la liste |
void clear(); | Vide complètement la liste |
exemple de code
modifier/* Déclaration */
ArrayList<String> liste = new ArrayList<>(); // depuis Java 7, plus besoin d'indiquer le type dans le membre de droite
/* Ajout d'éléments */
liste.add(E e); // ajoute l'élément 'e' en fin de liste
liste.add(int indice, E e); // ajoute l'élément 'e' à l'indice 'indice'
/* Taille */
liste.size(); // donne la taille de la liste
liste.isEmpty(); // indique si elle est vide
/* Accès */
liste.get(int indice); // renvoie l'élément se trouvant à l'indice 'indice'
/* Remplacement */
liste.set(int indice, E e); // remplace l'élément 'e' se trouvant à l'indice 'indice'
/* Recherche */
boolean contientE = liste.contains(E e); // indique si l'élément 'e' est présent
int indice = liste.indexOf(E e); // renvoie l'indice de la première occurrence de l'élément dans la liste
/* Suppression */
liste.remove(int indice); // enlève l'élément se trouvant à l'indice 'indice'
liste.remove(E e); // enlève l'élément 'e'
/* Parcours */
for (int i = 0; i < liste.size(); i++) { // for "normal"
System.out.println(liste.get(i));
}
for (String mot : liste) { // foreach
System.out.println(mot);
}
méthode
modifierUne méthode est l'équivalent du module du langage de description d'algorithmes.
Une méthode permet de découper le code en plusieurs parties afin de :
- le réutiliser
- scinder la difficulté
- faciliter le déverminage
- accroitre la lisibilité
- diviser le travail
Comment ?
- Elle a un nom qui décrit tout ce que le code fait
- Elle résout un sous-problème bien précis
- Elle est fortement documentée
- Elle est la plus générale possible
- Elle tient sur une page
Une méthode est une sorte de boite noire : elle reçoit des données, et renvoie un résultat.
Pour l’utiliser, on doit savoir :
- Son nom
- Quoi lui donner
- Ce qu'elle retourne
- Mais pas comment elle fait
Pour appeler une méthode :
- À partir du code d'une autre classe : NomClasse.nomMéthode(...)
- Si on est dans la même classe : on indique directement le nom de la méthode
Il est essentiel de commenter chaque méthode :
- Pour savoir pourquoi et comment l’utiliser
- Pour la comprendre et ainsi pouvoir la corriger et/ou la modifier
On utilise pour cela la documentation (Javadoc)
Passage de paramètres : En logique, 3 passages de paramètres : en entrée, en sortie, en entrée-sortie. En Java, uniquement par valeur :
- la valeur est copiée dans le paramètre
- ≈ paramètre en entrée
Conclusion :
- Une méthode fait une et une seule chose
- Une méthode possède un nom explicite
- Une méthode est fortement documentée
new
modifiercas d’usage
modifierL’opérateur new
sert à instancier une classe. C’est-à-dire créer un nouvel objet .
Pour créer cet objet, on fait appel à une méthode spéciale de la classe : le constructeur.
Généralisation : [class] [nom du nouvel objet] = new [class]([arguments du constructeur])
exemple de code
modifierScanner clavier = new Scanner(System.in)
Object
modifiercas d’usage
modifierun objet est une donnée structurée contenant des attributs et des fonctionnalités.
Pour effectuer des opérations sur un objet, on fait appels à des méthodes de l'objet. les opérateurs == et !=, à l'instar des primitifs, sont utilisables sur un objet.
un objet dispose de 2 types de méthodes : getters/setters // accesseurs/mutateurs. get : récupérer les attributs d'un objet ; renvoi une valeur. set : modifier les attributs d'un objet ; méthode void le plus souvent; peut renvoyer un booléen.
Pour fonctionner, certaines méthodes utilisent des paramètres d'appels.
==//!= permettent uniquement de vérifier si deux variables objets référencent le même objet. Pour vérifier si ces deux variables objets ont le même contenu, il faut faire appel à la méthode equals.
package
modifierL'API désigne la bibliothèque standard Java. Elle contient des milliers de classes qui sont regroupées en packages.
Un package
- regroupe les classes liées
- permet l'unicité des noms de classe (nom complet/qualifié :
package.Classe
)
Nom d'un package :
- identifieurs séparés par des points
- tout en minuscules
- généralement adresse internet inversée (unicité) :
be.heb.esi.java1
,org.junit.junitCore
Pour utiliser une classe d'un package donné, soit on indique le nom qualifié, soit on utilise import
qui crée un raccourci (voir import).
Pour créer une classe dans un package, on indique package nom_package;
en tant que première instruction du fichier.
Scanner
modifiercas d’usage
modifierLa classe Scanner
permet d'analyser des types primitifs et des chaines de caractères. Un objet de type Scanner
découpe en tokens ce qu’il reçoit en entrée, en utilisant un délimiteur (par défaut, l'espace).
On peut par exemple lire un entier depuis System.in
(généralement le clavier) en utilisant la méthode nextInt()
, un token en utilisant next()
, etc.
Les méthodes hasNextInt()
, hasNext()
, hasNextLine()
, etc. permettent de vérifier que le token en entrée peut bien être interprété comme un entier, un token, une ligne, etc.
exemple de code
modifierpublic static void lireClavier() {
Scanner clavier = new Scanner(System.in);
int nombre;
String mot;
String phrase;
nombre = clavier.nextInt();
mot = clavier.next();
phrase = clavier.nextLine();
}
Serializable
modifierUne classe doit implémenter Serializable
pour être sérialisable.
- Pas de méthode, sert juste de tag
- Tous ses attributs doivent aussi être sérialisables
La sérialisation est utilisée pour
- la communication réseau entre processus Java
- la sauvegarde des données d'une application :
- Pas très efficace → tout est lu ou sauvé en bloc
- La classe ne doit pas avoir changé entre le moment de l'écriture et le moment de la relecture → problème de pérennité de l'information
static
modifierLe mot-clé static
s'applique aux membres (attributs et méthodes)
- N'est plus un membre de l’objet (instance de la classe) mais un membre de la classe
- Est partagé par toutes les instances
Un attribut statique
- existe en un seul exemplaire
- est initialisé lors du chargement de la classe (une seule fois)
- utilisation courante : constantes
Une méthode statique
- ne peut pas accéder aux membres des instances
- utilisation courante : méthodes non objets
À l'extérieur de la classe, on préfixe par le nom de la classe ou par un objet de la classe (non recommandé).
import static
crée un raccourci pour l'accès aux membres statiques.
super
modifiersuper
est lié à l'héritage.
super(param1, param2)
appelle le constructeur de la classe parente, ou superclasssuper.attribut
accède à l'attribut de la superclassesuper.méthode()
accède à la méthode de la superclasse
switch
modifiercas d’usage
modifierLe switch
est proche du selon que
utilisé en logique.
- L'expression à évaluer est de type limité : char, byte, short, int ou String
- Les expressions constantes sont toutes différentes
- On utilise un
break
pour terminer uncase
- On peut omettre le
default
, mais s'il apparait, il doit être unique (et mis à la fin de préférence) - Les blocs sont admis mais pas recommandés
Le switch
ne permet pas de traduire le selon-que avec condition. On utilise alors if
- else if
.
exemple de code
modifierswitch (jour) {
case 0: System.out.println("Lundi"); break;
case 1: System.out.println("Mardi"); break;
case 2: System.out.println("Mercredi"); break;
case 3: System.out.println("Jeudi"); break;
case 4: System.out.println("Vendredi"); break;
case 5: System.out.println("Samedi"); break;
case 6: System.out.println("Dimanche"); break;
default: System.out.println("Erreur");
}
tableau à 1 dimension
modifierun tableau tab[n] est une variable pouvant contenir n données de types primitifs ou Objets. chaque donnée est référencé a l'indice n-1 dans le tableau. il est indispensable au parcours du tableau avec une boucle for. pour une boucle foreach, le type de donnée est suffisant. Un tableau peut s'utiliser en paramètre d'une fonction.
final int MAX = 10;
int[] list = new int[MAX];
// Remplit le tableau
for (int i = 0; i < MAX; i++)
{
list[i] = i * 10;
}
// On change la quatrième valeur
list[3] = 999;
// On affiche le contenu du tableau
for (int i = 0; i < MAX; i++)
{
System.out.print (list[i] + " ");
}
tableau à 2 dimensions
modifierun tableau tab[n,m] à 2 dimensions peut être considéré comme un tableau contenant des références vers des tableaux. chaque donné peut être retrouvé grâce à son indice dans le tableau n, puis son indice dans le tableau m.
int[][] liste = {{1, 2, 3}, {4, 5, 6}};
for (int i = 0; i < liste.length; i++)
{
for (int j = 0; j < liste[0].length; j++)
{
System.out.print (liste[i][j] + " ");
}
System.out.println();
}
tests unitaires
modifierLes tests unitaires sont des tests de chaque méthode.
- Fait-elle ce qu'elle est sensée faire ?
- C'est défini par la spécification (documentation)
- Idée : si chaque méthode est correcte → le tout est correct
- Pas forcément suffisant (exemple : ne teste pas la performance) → d'autres types de tests existent
Plan de tests
modifierTester une méthode ne s'improvise pas.
- Besoin d'un plan reprenant les tests à effectuer
- Quelles valeurs de paramètres ?
- Quel est le résultat attendu ?
- Préparé pendant que l’on code (ou même avant et éventuellement par une autre personne)
- Permet de s'assurer que l’on teste tous les cas
On ne peut pas tester toutes les valeurs possibles.
- Choisir des valeurs représentatives
- Cas généraux / particuliers
- Valeurs limites
- Il faut imaginer les cas qui pourraient mettre en évidence un défaut de la méthode
On s'inspire des erreurs les plus fréquentes en programmation.
- On commence/arrête trop tôt/tar une boucle
- On initialise mal une variable
- Dans un test, on se trompe entre < et ≤
- Dans un test, on se trompe entre && et ||
- ...
C'est un savoir-faire → importance de l'expérience
Quand tester ? Le plus souvent possible.
- Erreur plus facile à identifier/corriger
- Idéalement après chaque méthode écrite
Que tester ? Tout.
- Le nouveau code peut mettre en évidence un problème dans le code ancien (régression)
JUnit
modifierComment tester ? JUnit (par exemple).
- Le programmeur fournit les tests ;
- JUnit exécute tous les tests et ;
- établit un rapport détaillant les problèmes
En pratique
modifierLa classe de test contient une méthode de test par cas.
- Autonome (ne reçoit rien ni ne retourne rien)
- Contient des affirmations
- Appel de la méthode à tester
- Comparaison entre le résultat attendu et le résultat obtenu
Comment lancer les tests ?
java org.junit.runner.JUnitCore ClasseTest
Résultat ?
- Nombre de (méthodes de) tests effectués / réussis
- Détails sur les tests ratés :
- Nom du test
- Résultat obtenu comparé au résultat attendu
On teste aussi les exceptions.
/* Exemple de code à tester */
package be.heb.esi.java1;
public class Outil {
public static int max(int[] tab) {
int max = 0;
if (tab == null) {
throw new IllegalArgumentException("Le tableau ne peut être vide");
}
for(int i=0; i<tab.length; i++) {
if (tab[i]>max) {
max = tab[i];
}
}
return max;
}
}
/* Exemple de classe de test */
package be.heb.esi.java1;
import org.junit.Test; // Pour que @Test soit connu
import static org.junit.Assert.∗; // Pour assertEquals
public class OutilTest {
@Test
public void max_cas1() {
int[] tab = {1, 3, 0, 2};
assertEquals(3, Outil.max(tab));
}
@Test
public void max_cas2() {
int[] tab = {−1, −3, −4, −2};
assertEquals(−1, Outil.max(tab));
}
@Test(expected=IllegalArgumentException.class)
public void max_cas_null()
int[] tab = null;
Outil.max(tab);
}
// etc.
}
this
modifierLe mot-clé this
est une référence à soi-même. Il est implicite lors d'une utilisation directe du membre.
Règle : un paramètre/une variable locale masque un attribut. this
permet d'accéder à l'attribut masqué.
Certains l'utilisent systématiquement pour une meilleure lisibilté.
this
peut être utilisé lorsque les constructeurs d'une même classe se ressemblent. C'est plus facile si un constructeur appelle l'autre. this
doit alors être la première instruction.
/* Constructeurs de la classe Étudiant */
public Étudiant(int numéro, String nom, int année, boolean doubleur, boolean ancien) {
this.numéro = numéro;
this.nom = nom;
this.année = année;
this.doubleur = doubleur;
this.ancien = ancien;
}
public Étudiant(int numéro, String nom) {
this(numéro, nom, 1, false, false);
}
throw
modifierthrow
, à ne pas confondre avec throws
, permet de lancer une exception. Toutes les exceptions sont de type java.lang.Throwable
.
throw
nécessite un seul argument : un objet lançable.
public static double racineCarrée(double nombre) {
if (nombre < 0) {
throw new IllegalArgumentException("Le nombre doit être positif");
}
// ...
}
throws
modifierSi une méthode est capable de lancer une exception qu'elle ne gère pas, elle doit le préciser afin que les appelants de la méthode puissent se prémunir contre cette exception. On réalise cela en incluant la clause throws
dans la déclaration de la méthode. Cette clause liste les types d'exceptions que la méthode peut lancer. Si celles-ci ne sont pas déclarées, une erreur de compilation se produira.
Si la méthode lance plusieurs exceptions, on les déclare en les séparant par des virgules.
public void f() throws IllegalArgumentException, IOException {
// ...
if (...) {
throw new IllegalArgumentException("...");
} else if (...) {
throw new IOException("...");
}
// ...
}
toString
modifiertoString()
est une méthode de la classe java.lang.Object
. Elle renvoie une représentation textuelle de (l'état de) l'objet.
Par défaut, elle renvoie une chaine de caractères comprenant le nom de la classe de laquelle l’objet est instancié, le caractère @ et la représentation non-signée hexadécimale du hash code de l'objet.
Il est conseillé de la réécrire dans toutes les sous-classes.
public class Personne {
private String nom;
private String prénom;
public Personne(String nom, String prénom) {
this.nom = nom;
this.prénom = prénom;
}
@Override
public String toString() {
return "Nom : " + this.nom + "\nPrénom : " + this.prénom;
}
}
try-catch
modifiergénéralement associé a catch
, try permet de tester un bout de code susceptible de créer une Exception, et de gerer celle-ci grâce au catch, ou multi-catch.
Si le catch ne reprend pas l'Exception levé par le try, le programme s'arrete avant de reprendre son cours.
Si le catch s'exécute, le programme reprend son cours après le bloc try-catch.
le try peut aussi s'utiliser avec finally; le catch n'est alors pas indispensable.
type primitif vs référence
modifierToute donnée a un type :
- Cohérence sémantique
- Allocation mémoire adaptée
Différents types :
- primitifs prédéfinis : booléen, entier, réel
- références prédéfinis : tableaux, String, etc.
- références définis par le programmeur
Allocation mémoire :
- type primitif
- Indique la zone mémoire (sur la pile/stack) où se trouve la valeur
- type référence
- La zone mémoire contient l'adresse de la zone mémoire (sur le tas/heap) contenant la valeur (indirecction)
La méthode pour déterminer si deux valeurs sont égales est différente selon que ce soit un type primitif (les valeurs sont comparées) ou un type référence (les références sont comparées).
types primitifs et conversions
modifierUne conversion peut être implicite par affectation ou par promotion arithmétique. Lorsqu'elle est explicite, on fait appel a un opérateur de cast. Exemple: float f = (float) x; //cette conversion explicite étant sans perte, elle pourrait se faire par simple affectation.
Conversions sans perte :
De | Vers... |
---|---|
byte | short, int, long, float ou double |
short | int, long, float ou double |
int | long, float ou double |
long | float ou double |
float | double |
Conversions avec perte :
De | Vers... |
---|---|
short | byte ou char |
char | byte ou short |
int | byte, short, ou char |
long | byte, short, char ou int |
float | byte, short, char, int ou long |
double | byte, short, char, int, long ou float |
visibilité (private, ...)
modifierEn Java, 4 visibilités :
- public : visible dans toutes les classes →
public
- privé : accessible uniquement dans la classe où le membre est utilisé →
private
- paqueté : visible dans toutes les classes du
package
- protégé : accessible uniquement dans le package où il se trouve (pas vu en première) →
protected
Rappel de bonne pratique : attributs privés / méthodes publiques