# 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
### Cas d’usage

Le 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
## break/continue
### cas d’usage
#### break

break 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.
* 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

continue 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.
* Si pas d'étiquette → recommence la première instruction répétitive englobante
* Si étiquette → recommence la boucle étiquetée

### exemple de code
## constructeur
### cas d’usage

Un 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
## conversions
### cas d’usage

(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 de a ← 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
### cas d’usage

L'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
### cas d’usage

Une é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
## equals
### cas d’usage

La 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
### cas d’usage

Le 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
## for
### cas d’usage

La 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
## foreach

É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.

## I/O
### cas d’usage

I/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

Voir aussi : java.io

## i++/++i
### cas d’usage

++ 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’expression i++
** i est incrémenté

### exemple de code

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 valeur 5 et on incrémente i (qui vaut 6) mais l'évaluation est faite avant, i++ vaut donc 5 ;
* On évalue à présent ++i. D'abord on incrémente et i passe à 7. On évalue alors i donc ++i vaut 7 ;
* 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çoit 12 ;
* On a donc bien a = 12 et i = 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
### cas d’usage

Le 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
## implements
### cas d’usage

implements 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
## import

Pour 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.

## instanceof

L'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.

## instruction-expression
### cas d’usage

* 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
## liste
### cas d’usage

Une 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
## méthode

Une 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
### cas d’usage

L’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
## Object
### cas d’usage

un 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

L'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
### cas d’usage

La 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
## Serializable

Une 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

Le 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

super est lié à l'héritage.
* super(param1, param2) appelle le constructeur de la classe parente, ou superclass
* super.attribut accède à l'attribut de la superclasse
* super.méthode accède à la méthode de la superclasse

## switch
### cas d’usage

Le 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 un case
* 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
## tableau à 1 dimension

un 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.

## tableau à 2 dimensions

un 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.

## tests unitaires

Les 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

Tester 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

Comment 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

La 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 ?
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.

## this

Le 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.

## throw

throw, à 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.

## throws

Si 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.

## toString

toString 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.

## try-catch

gé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

Toute 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

Une 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, ...)

En 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
| Glossaire | Sommaire |