JAVA
Cours et TP n° 02
Bases du langage Bertrand LIAUDET
SOMMAIRE
SOMMAIRE 1
JAVA – BASES DU LANGAGE 3
Les variables 3
Déclaration 3
Nom 5
Les 4 types de base (types primitifs ou types natifs) 5
Pointeur 5
Valeur par défaut 5
Valeurs littérales 6
Conversion : « cast » 6
Les constantes : final 6
Les opérateurs 6
Exemple 6
Les tableaux 8
Déclaration et instanciation 8
Utilisation 8
Tableau à dimension > 1 9
Taille du tableau : tab.length 9
Méthodes pour les tableaux 9
Les chaînes 11
Déclaration et instanciation 11
Exemple 11
Méthodes pour les chaînes 12
Les structures : vers la P.O.O. 14
Structure = Classe 14
Déclaration et instanciation 14
Utilisation d’une structure dans le Main 14
Tableau de structures 15
Vers la P.O.O : notion de constructeur 16 P.O.O 17
Contrôle de la séquence 19
Tests 19
Boucles 20
Débranchement 21
Fonctions 22
Remarques préliminaires 22
Exemple 22
Syntaxe 23
Qualificateurs 23
Usages des fonctions (ou méthodes) : 23
Mode de passage des paramètres 24
Récursivité 24
Saisie et affichage 25
Affichage 25
Saisie 25
Exception 26
Le problème 26
La solution : un canal dédié aux exceptions : throws et throw 26 La récupération d’exception : 1 try … N catch … 1 finally 27
Paquetage (package) 29
Présentation 29
Hiérarchie des paquetages standards 29
Syntaxe 29
Exemples 29
Deprecated 30
CLASSPATH 30
JAR 31
Présentation 31
JAR exécutable 31
Fabrication d’un JAR 31
Référence 31
TP 32
Edition sept 2018
JAVA – BASES DU LANGAGE
Les variables
Déclaration
Une variable est un espace mémoire qui peut recevoir une valeur.
Les variables peuvent être déclarées de différentes manières : selon le type de déclaration, on aura un type de variable particulier avec une durée de vie et une visibilité particulière.
4 types de variables Ø Variables locales
Les variables déclarées dans des fonctions sont des variables locales.
Leur durée de vie et leur visibilité est limitée au bloc dans lequel elles ont été déclarées.
En général, il s’agit d’une fonction. On peut aussi les déclarer dans une boucle for.
Ø Paramètres formels
Les variables déclarées en paramètre d’une fonction sont des paramètres formels.
Ils sont instanciés à chaque appel de la fonction.
Ø Variables d’instance = attributs ou champs
Les variables d’instance sont déclarées en attribut dans une classe. Elles seront instanciées avec l’instanciation de l’objet. Elles sont accessibles par le nom de l’objet qui les instancie. Elles existent en autant d’exemplaires qu’il y a d’objets instanciés. Une variable d’instance existe tant que l’instance existe.
Ø Variables de classe (mot clé « static »)
Les variables de classe sont déclarées en attribut dans une classe comme les variables d’instance, mais on y ajoute le mot clé « static » Elles sont accessibles par le nom de la classe. Elles n’existent qu’en un seul exemplaire. Une variable de classe existe pendant toute la durée de vie de l’application.
L’accès aux variables (et aux fonctions)
Les variables (et les fonctions) peuvent être « private », « protected », « public » ou sans caractéristiques d’accès.
• Les variables (et les fonctions) « public » sont accessibles par tout le monde de partout.
• Les variables (et les fonctions) « private » sont accessibles uniquement dans le code de la classe qui les contient.
• Les variables (et les fonctions) sans caractéristiques sont accessibles par tout le monde dans le package. La notion de package sera abordée plus précisément dans le chapitre « base de la programmation objet – suite ».
• Les variables (et les fonctions) « protected » sont accessibles uniquement dans le code de la classe qui les contient et dans le code de ses sous-classes (ses enfants). La notion de sous- classe et de variables protected sera abordée plus précisément dans le chapitre « héritage ».
Exemple
public class Personne{
private String nom;
---à nom : variable d’instance=attribut private String prenom; ---à idem private int anneeNaissance; à idem
public Personne(String nom, String prenom, int anneeNaissance) {
---à nom, prenom, anneeNaissance : 3 paramètres formels this.nom=nom;
---àthis.nom : variable d’instance, nom : parametre formel
this.prenom=prenom; ---à idem
this.anneeNaissance=anneeNaissance; ---à idem }
public String toChar(){
return nom+" "+prenom+" "+anneeNaissance;
---à nom, prenom, anneeNaissance : 3 Variables d’instances }
}
public class Main {
public static void main (String args[]) { ---à args : 1 paramètre formel
Personne[] monTab;
--à monTab: variable locale
monTab = new Personne[5];
monTab[0]=new Personne("toto3", "lolo", 1995);
monTab[1]=new Personne("tata", "lala", 1996);
monTab[2]=new Personne("titi", "lili", 1997);
monTab[3]=new Personne("tutu", "lulu", 1996);
monTab[4]=new Personne("toutou", "loulou", 1995);
for(int i=0 ; i<monTab.length; i++) { --à i: variable locale
System.out.println("tab["+i+"]="+monTab[i].toChar() );
} }
}
Nom
Règles de formation
• Commence par une lettre
• Constituée d’autant de lettres, chiffres ou ‘_’ qu’on veut
• Majuscules et minuscules sont distinguées.
• Un nom de variable ne doit pas reprendre un mot-clé du langage.
Usage
Le nom d’une variable est en minuscule. On met des majuscules à chaque nouvelle partie signifiante dans le nom de la variable : « maVariable ». C’est le camelCase.
Les 4 types de base (types primitifs ou types natifs) Numérique : byte, short, int, long
byte [-128, +128], short [-32768, +32767], int [-2 147 483 648, 2 147 483 647], long : encore plus grand.
byte [1 octet], short [2 octets], int [4 octets], long [8 octets]
Décimaux : float, double
float [1.4 E -45, 3.4.. E +38]; double [4,9 E -324, 1,79.. E 308]
float [4 octets], double [8 octets]
caractère : char char : 2 octets.
128 premiers caractères : ASCII. Jusqu’à 256 : alphabet latin accentué. Le reste : autres alphabets.
\t: tabulation, \b: backspace, \n: saut de ligne, \r: retour chariot, \’: quote, \”: double quote, \\:
antislash.
\uXXXX : X en hexa (0 à EF): code sur 2 octets.
booléen : boolean
boolean : vaut true ou false, et rien d’autre !.
Pointeur
Pas de pointeur en java !
Pas de pointeurs explicites mais des pointeurs implicites (des références) : des objets, des tableaux, des chaines de caractères.
Pas d’arithmétique de pointeurs (indirection, addition, soustraction, etc.).
Valeur par défaut
Toutes les variables d’instance (les attributs) valent 0 par défaut (false pour les booléens).
Par contre, les variables locales doivent être initialisées.
Valeurs littérales 10 // int par défaut
short s=10 ; // ce sera bien un short
10L //10 est considéré comme un long. On peut mettre l ou L.
0x0C // hexa : on commence par 0x, puis 0C en hexa = 12 014 // octal : on commence par 0, puis 14 en octal = 12 3.45 // double par défaut
float=3.45 : c’est bien un float
3.45f // casté en float. On peut mettre F, ou d pour double ou D.
x=3.45e3 // double par défaut. Vaut 3.45 *1000 (10 puissance 3)
Conversion : « cast » Deux techniques :
• F, F, l, L, etc. en fin de valeur littérale,
• (type) devant une valeur ou une variable Principes
Les entiers se transforment tous en réels.
Un « petit » peut passer dans un « grand » mais pas le contraire sans risque de perte d’informations.
Exemple
Int a=1, b=2 ;
Float c=a/2 ; // c vaut 0 car c’est une
Les constantes : final
Une variable est une variable dont on ne peut pas modifier la valeur.
Elle est déclarée en la précédant du mot clé : « final ».
final double PI=3.14 ;
Par convention, le nom des constantes est en majuscules.
En général, les constantes sont des variables de classes.
Les opérateurs
Classiques : +, - , /, *, %, (, ), ==, !=, <, <=, >, >=
La division est entière si les termes sont entiers, réelle sinon.
Exemple
public class TestVar{
public static void main (String args[]) {
// les variables locales doivent être initialisées avant d'être utilisées
final float PI=3.14f ; int n = 1;
float x ; char c ; boolean b ; x = 2*PI + n ; c='A';
b=true ;
System.out.println("PI = "+PI);
System.out.println("n = "+n);
System.out.println("x = "+x);
System.out.println("c = "+c);
System.out.println("b = "+b);
if(b) System.out.println("b = "+!b);
if(c=='A') System.out.println("c = 'A' : "+c);
else System.out.println("c != 'A' "+c);
int aa=1, bb=2;
float cc=aa/bb; // division entière System.out.println("cc : "+cc);
cc=aa/(float)bb; // division réelle System.out.println("cc : "+cc);
} }
Les tableaux
Déclaration et instanciation Déclaration
int[] monTab ; // déclaration d’une variable sans instanciation ou
int monTab[] ; // déclaration d’une variable sans instanciation
Attention, on ne peut pas écrire : int monTab[3] ;
type[] définit un type tableau en tant que classe la taille est variable. Accesible par le « .length ».
Par défaut : null.
Instanciation
monTab=new int[3] ; // instanciation de la variable ou bien
int [] monTab={12, 18, 9} ; // déclaration et instanciation Instance partagée : notion de référence
int[] t, monTab={12, 18, 9} ;
t=montab ; // si on modifie t ça modifie monTab
Utilisation Exemple 1
montTab[0]=12 ; montTab[1]=18 ; montTab[2]=19 ;
for(int i=0 ; i<monTab.length -1; i++) { System.out.println("tab[“+i+”]=”+tab[i]);
} Exemple 2
/**
* Déclaration de la classe principale de l’application * Programme pour tester l’usage des tableaux
*/
public class Tableau{
/** main : Fonction d’entrée dans toute application java */
public static void main (String args[]) {
/* déclaration du tableau */
int[] monTab;
/* création du tableau */
montTab=new int[args.length];
/* intialisation du tableau */
for (int i=0 ; i<=args.length; i++) { monTab[i]=Integer.parseInt(args[i]);
}
System.out.println();
/* affichage du tableau */
for(int i=0 ; i<monTab.length; i++) {
System.out.println("tab["+i+"]="monTab[i]);
} } }
Tableau à dimension > 1
int[][] matrice ; // déclaration d’une var. sans instanciation matrice=new int[3][2] ; // instanciation de la variable
int[][] matrice ={{12, 18, 9}, {8, 20, 1}, {2, 8, 6}} ; //
déclaration et instanciation
Taille du tableau : tab.length
tab.length donne le nombre d’éléments du tableau.
En cas de dépassement, on obtient une erreur : ArrayIndexOutOfBoundException
matrice.length donne le nombre de lignes de la matrice.
matrice[0].length donne le nombre de colonnes de la première ligne de la matrice.
En cas de dépassement, on obtient une erreur : ArrayIndexOutOfBoundException
Méthodes pour les tableaux API
Classe : java.util.Arrays
https://docs.oracle.com/javase/10/docs/api/java/util/Arrays.html
Toutes les méthodes sont listées. Si on clique dessus, on obtient le détail du fonctionnement de la méthode.
Quelques méthodes remarquables
• length : taille du tableau
• sort : trier un tableau
• binarySearch : rechercher dans un tableau trié
• toString : tranformer le tableau en chaîne de caractères, entre crochets
• deepToString : toString pour tableau à dimension > 1
• copyOf : copier un tableau dans un autre (ou lui-même), en modifiant sa taille si on le souhaite. Permet donc de redimensionner un tableau.
• copyOfRange : copier une partie d’un tableau dans un autre (ou lui-même). Permet donc de redimensionner un tableau.
• equals : comparer les contenus deux tableaux.
• deepEquals : Equals pour tableau à dimension > 1
• fill : remplir toutes les cases d’un tableau avec la même valeur.
Usages
A noter que les méthodes sont presque toutes « static ».
On écrira donc par exemple : Arrays.sort(monTab);
Ou encore
Arrays.equals(tab1, tab2); // comparaison des contenus.
Attention, on peut aussi écrire
tab1.equals(tab2); // compare les référence ó tab1 == tab2
le equals vient alors de la classe parente : ici « Object » qui propose equals() mais aussi toString() qui ne sont pas des méthode « static »
Les chaînes
Déclaration et instanciation Déclaration : classe String
String ch ; // déclaration d’une chaîne sans instanciation String : classe.
Taille : variable.
Par défaut : null.
Instanciation
String ch1="Bonjour"; // déclaration et instanciation ou bien
String ch2=new String("Bonjour"); déclaration et instanciation ou bien
ch1= "Au revoir " ; instanciation seule La valeur d’une chaîne n’est pas modifiable.
Toute modification est en réalité une nouvelle instanciation.
Instance partagée : notion de référence String ch, ch1="Bonjour";
ch=ch1 ; Accès à un caractère
Attention : on ne peut pas écrire ch[0] !!!
String ch="Bonjour";
char c = ch.charAt(0) ;
Exemple /**
* Déclaration de la classe principale de l’application * Programme pour tester l’usage des chaînes
*/
public class TestString{
/** main : Fonction d’entrée dans toute application java */
public static void main (String args[]) {
/* déclaration et instanciation des string */
String ch1="Bonjour";
String ch2=new String("l'IPI");
System.out.println(ch1);
System.out.println(ch2);
System.out.println(ch1 + ch2);
ch2="j'ai dit 2 fois \"bonjour l'IPI\"";
System.out.println(ch2);
String ch3 ;
ch3= "Au revoir " ;
System.out.println(ch3.toUperCase();
System.out.println(toUperCase("test " );
} }
Méthodes pour les chaînes API
Classe : java.lang.String
https://docs.oracle.com/javase/10/docs/api/java/lang/String.html
Toutes les méthodes sont listées. Si on clique dessus, on obtient le détail du fonctionnement de la méthode.
Quelques méthodes remarquables
• + : opérateur de concaténation
• concat : concaténer deux chaînes
• length : longueur de la chaîne
• charAt : extraction d’un caractère (le premier en 0)
• indexOf : renvoie la position de la première occurrence d’un caractère
• substring : extraction d’un morceau de chaîne (debut et fin en paramètre)
• equals : comparer deux chaînes, identique ou pas
• compareTo : comparer deux chaînes. 0 si identique, >0 si plus grand, <0 si plus petit
• toUpperCase : passer en majuscules
• toLowerCase : passer en majuscules
• concat : concaténer deux chaînes
• replace : remplacer un caractère par un autre partout dans la chaîne
• replaceAll : remplacer une chaîne par une autre partout dans la chaîne
• replaceFirst : remplacer la première occurrence d’une string par une autre
• trim : supprimer les espaces de début et de fin
• split : découper une chaîne avec une expression régulière Usages
A noter que les méthodes ne sont en général pas « static ».
On écrira donc par exemple :
ch1.equals(ch2); // comparaison des contenus.
« equals » est une méthode de la classe String. ch1.equals(ch2) veut dire qu’à partir de l’objet
« ch1» de la classe String, on accède à la méthode « equals ». Cette méthode prend une autre chaîne en paramètre et compare le contenu des deux chaînes pour renvoyer vrai ou faux si elles sont identiques ou pas.
Les structures : vers la P.O.O.
Structure = Classe
Il n’y a pas de structure en Java. Ce sont les classes de la programmation objet qui gère ça.
Pour déclarer une structure, on va donc déclarer une classe.
On va montrer dans ce paragraphe une façon de coder qui fait « comme si » on avait une structure, pour se rapprocher le plus possible d’une logique algorithmique.
On montrera ensuite l’évolution de cette façon de faire vers de la programmation objet.
Déclaration et instanciation
Déclaration : classe StructPersonnne
On travaille sur une structure à 3 champs (=attributs) : nom, mail et année de naissance.
public class StructPersonne{
public String nom;
public String mail;
public int anneeNaissance;
}// déclaration d’une chaîne sans instanciation La structure est une classe.
Elle sera déclarée dans un fichier séparé : StructPersonne.java.
On ajoute « public » devant le mot clé « class » : ça signifie qu’on pourra s’en servir.
Tous les attributs sont « public » : ça signifie qu’on pourra s’en servir comme on veut.
Instanciation
StructPersonne unePersonne=new StructPersonne();
Cette écriture permet de créer une variable (un objet) appelée « une personne ». On pourra maintenant donner des valeurs pour chacun des attributs.
Instance partagée : notion de référence StructPersonne p2
p2=unePersonne ;
Avec cette écriture, p2 et unePersonne font référence à la même personne concrète.
Utilisation d’une structure dans le Main /**
* Déclaration de la classe principale de l’application * Programme pour tester l’usage des structures
*/
public class Main{
{
public static void main (String args[]) {
StructPersonne unePersonne=new StructPersonne();
unePersonne.nom="toto1";
unePersonne.prenom="toto@truc.fr";
System.out.println("unePersonne =" +unePersonne.nom+" "
+unePersonne.prenom+" "+unePersonne.anneeNaissance );
StructPersonne p2;
p2=unePersonne; // p2 et unePersonne sont des références
p2.anneeNaissance=2000; // ça modifie p2 et unePersonne System.out.println("p2 =" +p2.nom+" "
+p2.prenom+" "+p2.anneeNaissance );
System.out.println("unePersonne =" +unePersonne.nom+" "
+unePersonne.prenom+" "+unePersonne.anneeNaissance );
} }
Tableau de structures
Déclaration : classe StructPersonnne
StructPersonne[] monTab;
monTab = new StructPersonne[5];
ou
StructPersonne[] monTab = new StructPersonne[5];
Syntaxe
MonType[] monTab = new MonType[5];
Utilisation d’un tableau de structures dans le Main Ø On se dote d’une fonction newPersonne
Elle permet de créer une personne à partir de la valeur de ses attributs.
Utilisation de la fonction :
StructPersonne personne =newPersonne("toto1", "toto@truc.fr", 1995);
Ø Déclaration et remplissage du tableau.
On remplit en utilisant la fonction.
StructPersonne[] monTab = new StructPersonne[5];
monTab[0]=newPersonne("toto1", "toto@truc.fr", 1995);
Ø Remarques syntaxique
Les fonctions de la classe Main (qui contient la fonction « main ») sont toutes « static ».
Pour le moment, la « class » et les fonctions sont « public ».
Ø Exemple complet public class Main {
public static StructPersonne newPersonne(String nom, String prenom, int anneeNaissance) {
StructPersonne unePersonne=new StructPersonne();
unePersonne.nom=nom;
unePersonne.prenom=prenom;
unePersonne.anneeNaissance=anneeNaissance;
return unePersonne;
}
public static void main (String args[]) {
StructPersonne[] monTab;
monTab = new StructPersonne[5];
monTab[0]=newPersonne("toto1", "toto@truc.fr", 1995);
monTab[1]=newPersonne("tata", "tata@truc.fr", 1996);
monTab[2]=newPersonne("titi", "titi@truc.fr", 1997);
monTab[3]=newPersonne("tutu", "tutu@truc.fr", 1996);
monTab[4]=newPersonne("toutou", "toutou@truc.fr", 1995);
for(int i=0 ; i<monTab.length; i++) { System.out.println("tab["+i+"]="
+monTab[i].nom+" "
+monTab[i].prenom+" "
+monTab[i].anneeNaissance );
} }
}
Vers la P.O.O : notion de constructeur
On va déplacer la fonction newPersonne dans la classe Personne Ø Constructeur
« newPersonne » aura forcément le nom de la classe. Ici : Personne(…) Ce type de fonction s’appelle « constructeur ».
On peut lui passer des paramètres. Ici :
public Personne(String nom, String prenom, int anneeNaissance)
Ø This
Le mot clé « this » permet en quelque sorte de créer une nouvelle personne : Personne unePersonne=this;
Ø Code
On obtient donc la classe suivante : public class Personne{
public String nom;
public String prenom;
public int anneeNaissance;
public Personne(String nom, String prenom, int anneeNaissance) {
Personne unePersonne=this;
unePersonne.nom=nom;
unePersonne.prenom=prenom;
unePersonne.anneeNaissance=anneeNaissance;
} }
Utilisation dans le Main
Le main est simplifié : on n’y trouve plus la fonction newPersonne.
Par contre, l’utilisation du constructeur se fait avec le mot clé « new » :
monTab[0]=new Personne("totoo", "lolo", 1995);
Ø Exemple complet public class Main {
public static void main (String args[]) {
Personne[] monTab;
monTab = new Personne[5];
monTab[0]=new Personne("totoo", "lolo", 1995);
monTab[1]=new Personne("tata", "lala", 1996);
monTab[2]=new Personne("titi", "lili", 1997);
monTab[3]=new Personne("tutu", "lulu", 1996);
monTab[4]=new Personne("toutou", "loulou", 1995);
for(int i=0 ; i<monTab.length; i++) { System.out.println("tab["+i+"]="
+monTab[i].nom+" "
+monTab[i].prenom+" "
+monTab[i].anneeNaissance );
} }
}
P.O.O
La classe Personne Ø code
public class Personne{
private String nom;
private String prenom;
private int anneeNaissance;
public Personne(String nom, String prenom, int anneeNaissance) {
this.nom=nom;
this.prenom=prenom;
this.anneeNaissance=anneeNaissance;
}
public String toChar(){
return nom+" "+prenom+" "+anneeNaissance;
} }
Ø Explications
Désormais les attributs sont private : principe d’encapsulation.
On a ajouté une fonction dans la classe : toChar() qui permet de retourner une chaine de caractères avec les information d’une personne.
La fonction toChar a entrée une personne et en sortie les infos de la personne.
Il n’y a pas de paramètres car la personne sera fourni avec l’usage de la fonction : on écrira : System.out.println( unePersonne.toChar() )
La classe Main Ø code
public class Main {
public static void main (String args[]) {
Personne[] monTab;
monTab = new Personne[5];
monTab[0]=new Personne("toto3", "lolo", 1995);
monTab[1]=new Personne("tata", "lala", 1996);
monTab[2]=new Personne("titi", "lili", 1997);
monTab[3]=new Personne("tutu", "lulu", 1996);
monTab[4]=new Personne("toutou", "loulou", 1995);
for(int i=0 ; i<monTab.length; i++) {
System.out.println("tab["+i+"]="+monTab[i].toChar() );
} }
}
Ø Explications
Dans la classe Main, on n’utilise plus directement les attributs de la classe Personne.
Etant devenus « private », ils sont inaccessibles. D’où l’écriture de la fonction toChar().
Contrôle de la séquence
Tests if
4 syntaxes possibles :
if (condition) une instruction
if (condition){
des instructions }
if (condition) ...
else
une instruction
if (condition) ...
else{
des instructions }
Le bon usage : toujours mettre des accolades elseif
Le elsief (tout attaché) n'existe pas mais on peut mettre une instruction unique if dans un else, ce qui donne un équivalent d'un elseif tout attaché.
Le bon usage : if (condition){
des instructions }
else if {
des instructions }
else if {
des instructions }
else {
des instructions }
switch
Le switch est équivalent à un elseif mais on n’est obligé de faire une comparaison d’égalité sur une seule variable. Il faut aussi faire un break pour sortir quand on passe par une branche du switch.
Le bon usage :
switch (expression) { case valeur1:
des instructions break;
case valeur 2:
des instructions break;
case valeur 3:
des instructions break;
default :
des instructions }
Boucles while
Le bon usage :
while(condition){
des instructions }
do while
Le bon usage : do{
des instructions }while(condition);
for
Le bon usage :
for(int i=0 ;i<n ; i++){
des instructions }
Ou:
for(int i=0 ; i<tab.length; i++) { des instructions
}
for sans indice int i=0;
for(int elt : monTab){
System.out.println("tab["+i++ +"]="+ elt);
}
Débranchement break et continue
le break permet de sortir de la boucle ou il se trouve, ou de sortir de la boucle auquel il fait référence.
Le continue permet d’aller à la fin de la boucle ou il se trouve, ou d’aller à la fin de la boucle auquel il fait référence.
Le bon usage 1 : sortie d’une boucle for(int i=0 ;i<n ; i++){
des instructions if (condition){
des instructions break; // ou continue }
des instructions }
Le bon usage 2 : sortie de boucles imbriquées – boucle avec étiquettes maboucle : while(condition){
des instructions
for(int i=0 ;i<n ; i++){
des instructions if (condition){
des instructions
break maboucle; // ou continue }
des instructions }
des instructions }
return
Le return permet de quitter la fonction (méthode) dans lequel il est utilisé.
Il permet aussi de renvoyer une valeur sur la sortie standard de la fonction (méthode) . goto
Pas de goto en java ! Le principal usage du goto, à savoir la sortie de boucles imbriquées, est pris en charge par les boucles avec étiquette et les débranchements de boucle avec étiquette.
Fonctions
Remarques préliminaires
Les fonctions sont toujours déclarées dans les classes. Dans un premier temps, on ne voit que la déclaration des fonctions « static » qui sont accessibles par le nom de leur classe. Les fonctions non « static » sont seulement utilisées (toUpperCase par exemple).
Exemple /**
* Déclaration de la classe principale de l’application * Programme pour tester l’usage des tableaux
*
* @author : INSIA */
public class Tableau2{
/** main : Fonction d’entrée dans toute application java */
public static void main (String args[]) {
/* déclaration du tableau */
int[] monTab;
/* création du tableau */
monTab=new int[args.length];
/* intialisation du tableau */
for (int i=0 ; i<args.length; i++) { monTab[i]=Integer.parseInt(args[i]);
}
System.out.println();
/* affichage du tableau */
int res=afficherTableau(monTab);
// on peut aussi écrire : Tableau.afficherTableau System.out.println
("Le tableau contient "+res+" elements");
} /**
* afficherTableau : Fonction d’affichage d’un tableau *
* @param Entrée : tab : le tableau à afficher * @param Sortie : affichage du tableau
* @param Return : la taille du tableau */
private static int afficherTableau (int[] tab){
System.out.println("Affichage du tableau :");
for(int i=0 ; i<tab.length; i++) {
System.out.println("tab["+i+"]="+tab[i]);
}
return tab.length;
}
}
Syntaxe
Une fonction est composée d’une en-tête (ou signature) et d’un corps.
La syntaxe est similaire à celle du langage C :
type nomFonction (type var1, type var2…) { instructions
}
Qualificateurs
« private » ajouté devant la signature rend la fonction accessible uniquement par les fonctions de sa classe (Tableau). On pourrait aussi mettre « public ».
« static » ajouté devant la signature rend la fonction accessible directement sans avoir besoin d’objet.
Usages des fonctions (ou méthodes) :
Méthodes de classe : définie avec un « static »
Dans ce cas, le nom de la méthode est préfixé par sa classe d’appartenance, sauf si l’appel de la méthode se fait dans la classe de définition de la méthode.
L’usage des méthodes de classes est équivalent à celui des fonctions de la programmation classique (pas objet).
Ø Exemples
System.out.println("Hello World JAVA");
resultat=Integer.parseInt(args[i-1]) ; monTab[i]=Integer.parseInt(args[i]);
int res=afficherTableau(monTab);
// ou alors : int res= Tableau.afficherTableau(monTab);
Ø Explications
La méthode « println » est définie dans la classe System du package java.lang (importé par défaut). Elle à une String en paramètre.
La méthode « parseInt » est définie dans la classe Integer du package java.lang (importé par défaut). Elle a une String en paramètre et elle renvoie un entier.
La méthode « afficherTableau » est définie dans la classe Tableau. Elle a un tableau en paramètre et elle renvoie un entier.
Méthodes d’instance : définie sans “static”
Dans ce cas, le nom de la méthode est préfixée par l’objet (la variable) auquel la méthode va s’appliquer. C’est un usage caractéristique de la programmation objet.
Ø Exemples
• if (args[i].equals("-")) {
• System.out.println(ch3.toUpperCase());
Ø Explications
La méthode “equals” s’applique à “args[i]” qui est une String. Cette méthode est donc définie dans la classe String du package java.lang (importé par défaut).. Elle reçoit une String en entrée : ici "-".
La méthode « toUpperCase() » s’applique à ch3 qui est une String. Cette méthode est donc définie dans la classe String du package java.lang (importé par défaut). Elle n’a pas de paramètres.
Mode de passage des paramètres
Le return permet de renvoyer des variables de type simple et des références vers des tableaux, des chaines, des objets. int[] maFonction(…) renvoie un tableau d’entiers.
Les variables de type simple sont forcément passées en entrée et ne peuvent pas être modifiée.
C’est un passage par valeur : c’est en réalité la valeur de la variable qu’on transmet.
Les références permettent la modification du référé dans la fonction. Toutes les références sont donc potentiellement en entrée et en sortie. La valeur de la référence ne sera par contre pas modifié.
On verra aussi que java gère un deuxième canal de sortie : la sortie en erreur (throws).
Récursivité
Le java permet d’écrire des fonctions récursives.
Saisie et affichage
https://docs.oracle.com/javase/10/docs/api/java/lang/System.html
Affichage
Affichage non formaté : print et println System.out.println(“Bonjour”);
« out » est une variable de classe de la classe System. Cette variable est de classe PrintStream.
La méthode println est définie dans la classe PrintStream.
println passe à la ligne.
print ne passe pas à la ligne.
Affichage formaté : printf
System.out.printf(“Bonjour %d\n”, i);
C’est l’équivalent du C.
%3d permet de formater un entier sur 3 caractères
%6.2f permet de formater un float sur 6 caractères avec 2 après la virgule
%g permet de formater un nombre « au mieux » automatiquement.
%-10s permet de formater une chaine de caractères sur 10 caractères (ça débordera si nécessaire) en callant de texte à droite.
Etc.
Saisie
Lecture non formatée (lire une chaîne jusqu’au retour chariot) String nom=System.console().readLine();
System.out.println(nom);
• On crée un objet Console (package java.io) avec la méthode console() de la classe System (package java.lang).
• A partir de l’objet Console, on accède à la méthode readline() qui permet de lire un chaîne de caractère jusqu’au retour chariot et qui retourne donc un objet chaîne de caractère.
• On pourra ensuite caster la chaîne lue.
Lecture typée
Ce mode de lecture sera abordé avec la programmation objet.
Exception
Le problème
Soit la fonction « inverse » qui renvoie l’inverse d’un réel.
En C, sans gestion d’erreur, la fonction s’écrit : double inverse(double a) {
return 1/a ; }
L’usage de la fonction pourra être : res = inverse(5);
Le problème est que si on passe “0” à cette fonction, le programme va « planter ».
Si on veut gérer le cas d’erreur, on devra écrire int inverse(double a, double * res) {
if (a==0) return 0 ; *res=1/a;
return 1;
}
L’usage de la fonction devra alors être : int ok;
double res;
ok = inverse(5, &res);
if (ok==0) printf(“ division par 0 impossible” ;
Le code est assez lourd et surtout on a perdu l’usage classique de la fonction dans une expression, du type : 4*inverse(3)
La solution : un canal dédié aux exceptions : throws et throw
La solution consiste à ce que le compilateur gère un deuxième canal de retour dédié aux exceptions.
Dans le code, le retour par ce deuxième canal se fait par le mot-clé « throw » : c’est l’équivalent d’un « return ».
Dans l’en-tête, le type de retour par ce deuxième canal se fait par le mot-clé « throws ».
En java, la fonction inverse s’écrira :
double inverse(double a) throws Exception {
if (a==0) throw new Exception("division par 0 impossible");
return 1/a;
}
L’usage de la fonction devra alors être : try{
res=inverse(5) ; }
catch(Exception e) {
System.out.println(e.getMessage());
}
Le code est alourdi par la présence du try.
Mais le premier avantage est que l’appel de la fonction est classique : inverse(5). On peut toujours intégrer la fonction dans une expression du type : 4*inverse(5).
Le deuxième avantage vient ensuite de la gestion des exceptions par le compilateur et du fait qu’on peut choisir le moment où on traite l’exception car celle-ci remonte la pile des fonctions appelantes.
On peut choisir notre message d’exception et le traiter comme on le souhaite. On le récupère avec le e.getMessage().
La récupération d’exception : 1 try … N catch … 1 finally Principes
• TRY : Le code à risque est placé dans un bloc « try ».
• CATCH : Le bloc « try » est suivi par un ou plusieurs blocs « catch » qui pourront prendre en compte différents types d’exception. Si aucune exception ne correspond, alors le moteur java remonte à la méthode appelante pour trouver une exception adaptée.
• FINALLY : Les blocs « catch » peuvent être suivi (facultatif) par un bloc « finally » qui sera exécuté dans tous les cas (sauf si le bloc « catch » fait quitter la méthode par un System.exit).
L’intérêt du bloc « finally » se justifie quand l’exception n’est pas traitée au niveau où elle est décelée.
Syntaxe try{
instructions ; }
catch(IOException e) { instructions ;
}
catch(Exception e) { instructions ; }
finally{
instructions ; }
Remaques
S’il y a plusieurs catch, seul le premier qui « matche » est traitée. C’est pourquoi on doit commencer par mettre les exceptions dérivées avant les exceptions de base.
En effet, une exception est un objet qui va se substituer à la variable du CATCH. Par exemple, si le try génère un objet exception de la classe IOException, on passera dans le catch IOException. Mais si le try génère un objet exception de la classe ArithmeticException, celui-
ci peut se substituer (selon le principe de substitution) au « e » du « catch(Exception e » car une ArithmeticException est une Exception.
Les erreurs les plus fréquentes
Division par 0 ArithmeticException
Référence nulle NullPointerException
Type illégal ClassCastException
Tableau de taille négative NegativeArraySizeException Dépassement de la limite d’un tableau ArrayIndexOutOfBoundsException
Format non valide NumberFormatException
Exemple de simple try catch Ø Code
public class TryCatch{
public static void main (String args[]) { int arg1, arg2=0;
try {
arg1=Integer.parseInt(args[0]);
}
catch(Exception e) { arg1=0;
}
System.out.println("arg1 : "+arg1);
try {
arg2=Integer.parseInt(args[1]);
}
catch(Exception e) {
System.out.println("exception levee : "+ e);
return;
}
System.out.println("arg2 : "+arg2);
} }
Ø Résultats
C:\ >java TryCatch arg1 : 0
exception levee : java.lang.ArrayIndexOutOfBoundsException: 1 C:\ >java TryCatch 1 1.2
arg1 : 1
exception levee : java.lang.NumberFormatException: For input string: "1.2"
Paquetage (package)
Présentation
Un paquetage est une bibliothèque de classes organisée de façon hiérarchique.
Le nom d’un paquetage est le nom du répertoire dans lequel se trouve la classe.
Les paquetages peuvent être rassemblés dans des archives « .zip » ou « .rar ».
Hiérarchie des paquetages standards java
java
lang util io applet awt
java.lang contient les classes fondamentales : String, Math, etc. Elle est importée par défaut.
Java.util contient les classes relatives aux collections, à de la gestion de dates, etc. Elle n’est pas importée par défaut. Il faut l’importer par exemple quand on utilise des Arrays.
java.io contient les classes relatives aux entrées-sorties javax
javax est une autre racine de paquetage qui contient des éléments plus récent et particulièrement la bibliothèque graphique Swing qui tend à remplacer la bibliothèque AWT.
Syntaxe
Inclusion de la classe dans un paquetage package nomPaquetage ; Importation d’une classe
import nomPaquetage.nomClasse;
Importation d’un paquetage complet import nomPaquetage.* ;
// à éviter car c’est peu informatif !
Exemples Arrays
/* Importation de la classe Arrays pour faire Arrays.sort() */
import java.util.Arrays;
Calendar, GregorianCalendar
import java.util.Calendar;
import java.util.GregorianCalendar;
...
// dans une classe : public int getAge(){
return new GregorianCalendar().get(Calendar.YEAR) - anneeNaissance;
Deprecated
A noter que certaines classes ou méthodes peuvent être devenues « deprecated ». Dans ce cas, il vaut mieux éviter de les utiliser, même si elles marchent encore, pour mieux assurer la pérénité du code.
CLASSPATH
La variable d’environnement CLASSPATH indique à la JVM où trouver les classes et bibliothèques de classes dont elle a besoin.
C’est l’équivalent du Path des OS.
JAR
Présentation
jar.exe est un utilitaire qui permet de compresser ses dossiers et package de fichiers java (de classes).
Il produit une archive .jar. C’est une archive qu’on peut ouvrir comme un zip par exemple.
JAR exécutable
L’intérêt de l’outils de de permettre de fabriquer des archives qui pourront être utilisées directement comme des programmes.
Fabrication d’un JAR En console
En console, on utilise l’utilitaire jar.exe.
Il faut créer un fichier de configuration particulier appelé : MANIFEST.MF Avec un IDE : Eclipse
Un IDE permet plus facilement de fabriquer des JAR.
Référence
https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html
TP
1) Coder la classe Tableau (dans le poly). Compiler. Exécuter.
2) Coder la classe TestString (dans le poly). Compiler. Exécuter.
3) Coder les classes d’utilisation d’une structure dans le main (dans le poly, version avant la POO). Compiler. Exécuter.
4) Coder les classes d’utilisation d’un tableau de structures dans le main (dans le poly, version avant la POO). Mettez l’affichage dans une fonction. Compiler. Exécuter. Générer la documentation avec javadoc.
5) Coder un programme qui résout une équation du premier degré en passant les paramètres en ligne de commande. Le programme séparera radicalement le calcul des résultats de l’affichage des résultats. On fera une version sans fonction et une version avec une fonction qui affiche les résultats à partir du nombre de solutions et des solutions calculées. Le principe de résolution est le suivant : l’équation à la forme aX+b=0. On fournit a et b pour résoudre l’équation. Si (a,b)=(0,0), il y a une infinité de solutions. Si (a,b)=(0, !=0), il n’y a pas de solution. Si a !=0, la solution est –b/a.
6) Ecrire un programme qui code le tri d’un tableau en utilisant la méthode du tri à bulle. Le programme récupèrera les données en ligne de commande, les affichera sur une seule ligne, puis les triera et les réaffichera sur une seule ligne une fois le tri effectué.
7) Coder un programme qui tri un tableau d’au moins 5 entiers fournis en ligne de commande, le tri en ordre croissant. Le programme affiche le tableau initial sur une seule ligne, puis le tableau trié sur une seule ligne, crée une copie de ce tableau avec les 5 éléments en plus initialisé à 0 et affiche le tableau en ordre décroissant.
Pour cet exercice, vous pouvez vous intéresser aux fonctions de manipulation des tableaux (classe Arrays). Cherchez l’usage de la fonction « sort ».
8) Ecrire un programme qui récupère en ligne de commande une phrase dont les mots sont séparés par des espaces. Le programme devra afficher le nombre d’arguments (il doit valoir 1), la phrase complète et le nombre de mots de la phrase.
9) Reprendre des exercices d’algorithmique.