Bases de java

types de variables

  • int pour stocker un entier en mémoire :   int n1 = 33, n2 = 12, n3 = 9, n4 = 100;
  • float pour stocker un nombre à virgule flottante :   float x = 12.103, y = 5f;
  • String pour stocker un texte (une chaîne de caractères).  Attention au S majuscule !   String maPhrase = "Bonjour, bienvenu !";
  • char pour stocker un caractère :   char lettre = 'B'; ou en unicode : char lettre = '\u0066';

NB : String porte une majuscule car ce n’est pas un type primaire ; et c’est aussi pour cette raison qu’on ne peut pas tester l’égalité de deux variables String chaine1 et chaine2 avec == mais avec la méthode equals()  :

L’égalité de 2 variables String se fait avec equals() :   if (chaine1.equals(chaine2)) { ... }

Les 8 types primaires :

Type Signification Taille
en octet
Plage de valeurs acceptées
boolean Valeur logique (booléen) 1 true ou false
char Caractère Unicode 2 '\u0000'  à  '\uffff'
(de 0  à  65535)
byte Entier très court 1 -128  à  +127 ENTIER
short Entier court 2 -32 768 à +32 767
int Entier 4 -231  à +231-1  ( sachant que 231 = 2×10)
long Entier long 8 -263  à +263-1  ( sachant que 263 = 9×1018 )
float Nombre décimal simple précision 4 ±2-149   à   ±2128 – 2104 DECIMAL
double Nombre décimal double précision 8 ±2-1074   à  ±21024 – 2971

Pour afficher un texte dans la console d’Eclipse :  System.out.println("chaine1 vaut " + chaine1);

Conversion de type = transtypage = casting : les types primaires peuvent être convertis au moyen de parenthèses :

// conversion : double => int
int x = (int)5.27e-2;  // donne x = 0

// conversion : char => int
char lettre = '8' ; // un caractère
int i = (int)lettre ; // i est l'entier 8

chaîne de caractère : String, char

char signifie un caractère (comme ‘a’, ‘Z’, ‘1’ …)  et String signifie chaîne de caractère (donc un texte).

  • Concaténer deux chaînes : +     ex : "hello"+"you"  donne    "helloyou"
  • Longueur d’une chaîne :   int n= maChaine.length();  donne le nombre de caractères de maChaine.
  • Comparer 2 chaînes :     if (chaine1.equals(chaine2)) {...}   car equals() teste l’égalité de 2 objets.
  • Conversion en majuscule/minuscule : ch=maChaine.toUpperCase();      ch=maChaine.toLowerCase();
  • Supprimer tous les espaces : ch=maChaine.trim();
  • Obtenir un caractère :  char c = maChaine.charAt(i);   pour obtenir le ième caractère de maChaine   sachant que le 1er caractère est numéroté 0.
  • Extraire la fin de chaîne : ch=maChaine.substring(d); renvoie la chaîne entre le d-ième caractère à la fin.
  • Extraire une partie de chaîne : ch=maChaine.substring(d, f); renvoie la chaîne entre le d-ième caractère et le f-ième.
  • Conversion de tous les caractères car1 en car2 : ch=maChaine.replace(car1, car2);
  • Conversion de tous les chaînes ch1 en ch2 : ch=maChaine.replaceAll(ch1, ch2);   ou replaceFirst() pour remplacer la 1ère  occurrence seulement.
  • Tester le début d’une chaîne : maChaine.startsWith(prefix,i) renvoie true si à l’entier i, maChaine commence par prefix.
  • Conversion d’un tableau de caractères => chaîne : chaine = String.valueOf(tabChar); pour obtenir un String à partir du tableau de char.
  • Conversion d’une chaîne  => tableau de caractères  : char[] tabChar = chaine.toCharArray();
  • Conversion d’un entier => chaîne  : ch=String.valueOf(n); avec  n : boolean, char, double, float, int, long, Object.
  • Conversion d’une chaîne => entier  : n=Integer.parseInt(maChaine);

Changer le i-ème caractère : 

String changeChar(int i, char car, String str) {
        char[] charTableau = str.toCharArray();
        charTableau [i] = car;
        return new String(charTableau);
}

nombres : modulo, division, Math

modulo  % : Dès qu’on veut qu’une action s’exécute 1 fois toutes les 4 étapes (ou 5 étapes …) on utilise la notion de « modulo » sur une variable i (qui est le compteur d’étapes) et on note i % 4. En réalité i % 4 est le reste obtenu lors de la division euclidienne de i par 4 (ce reste varie de 0 à 3).
i%4==0  signifie que i est divisible par 4 (ex : i=2016, 2020, …).
En revanche :  2017%4 = 1 ;  2018%4 = 2 ;  2019%4 = 3 ;  2020%4 = 0 …

for (int i = 2016 ; i<2100, i++) {
    System.out.println("Année : "+i);
    if (i % 4 == 0) System.out.println("Et, l'année "+i+" est bissextile");
}

Division selon les types :

La division de 2 entiers donne un entier, donc 5/2=2 .
La division d’un entier par un float donne un float (et vice-versa) donc 2.5/2 = 1.25

Exemple :  float z=5/2; donne z=2.0 (car le transtypage se fait après la division entière !)
Pour obtenir 2.5, il faut transtyper à l’intérieur de la division :  float z=5f/2f;

Outils mathématiques :

La librairie Math utilise des nombres de type double, float …  donc un transtypage risque d’être nécessaire. Exemple :  x = Math.pow( 2f, (double) n);

  • racine carrée : Math.sqrt(2.0)  donne 1.41..  [ détail : double abs(double a) ]
  • racine cubique : Math.cbrt(8)  donne 2  [ détail : double cbrt(double a) ]
  • valeur absolue : Math.abs(-3.0 donne 3  [ détail : float abs(float a) et int abs(int a)  et  long abs(long a) ]
  • puissance : Math.pow(2.0,3.0) donne 8 [détail : double pow(double a, double b) ]
  • exponentiel : Math.exp(5.0)  donne 148.41.. [détail : double exp(double a) ]
  • ln (logarithme népérien) : Math.log(5.0 donne 1.609.. [détail : double log(double a) ]
  • log (logarithme décimal) :  Math.log10(5.0)  donne 0.698.. [détail : double log10(double a) ]
  • arrondi entier (le +proche) : Math.round(-8.3) donne -8 [détail : long round(double a)  ou  int round(float a) ]
  • partie entière (arrondi entier par défaut) : Math.floor(-8.3) donne -9 [détail : double floor(double a) ].
  • arrondi entier par excès : Math.ceil(-8.3) donne -8  [détail : double ceil(double a) ]
  • min / max : Math.min(7.5,12) donne 7.5 . De même :  Math.max(). [détail : double min(double a, double b)  ou  float min(float a, float b)  ou  int min(int a, int b)  ou  long min(long a, long b) ]
  • cos  (angle en radian) :  Math.cos(). Idem pour Math.sin() et Math.tan(). [ détail : double cos(double a) ]
  • arccos()Math.acos() donne l’angle entre 0 et p radians. [détail : double acos(double a) ]
  • convertir un angle : degré <=> radian Math.toRadians(90) . Idem pour Math.toDegrees()
  • constantes :  p  est  Math.PI (3,14 …) et    e est Math.E  (le nombre d’Euler 2,7182..)

déclaration et création d’objet

Pour utiliser des objets, c’est un peu plus délicat car il faut faire 2 choses :

  1. Déclarer l’objet :  JButton boutonN1;
  2. Définir l’objet (allocation mémoire + construction) :    boutonN1 = new JButton(""+n1);

OU  faire les 2 étapes en une seule ligne : JButton boutonN1 = new JButton(""+n1);

En fait, JButton est une classe (une classe commence par une majuscule) et boutonN1 est un objet de cette classe. La création se fait avec l’opérateur new et comme java a besoin de la librairie des JButton pour faire cet objet donc il faudra faire CTRL+SHIFT+O pour ajouter l’import tout au début du code  import javax.swing.JButton;

Autre exemple, les couleurs :   Color violet = new Color(200,90,200);

Une classe est un moule. Un objet (aussi appelé instance) est un gâteau fabriqué à partir du moule.
On peut créer plusieurs objets à partir d’une classe.

instanciation d’un objet = déclaration de la référence + allocation en mémoire + construction (appel d’un constructeur)

tableaux

Ja_ArrayExgénéralités : tableau [ ] (à 1 dimension)

Construire un tableau nécessite 3 étapes :

  1. déclaration du tableau :   les crochets [] peuvent être placés avant ou après le nom du tableau (qui est en réalité l’adresse du tableau) :
    int ti [];  //tableau d’entiers
    char[] tc;  //tableau de caractères
  2. allocation mémoire : il faut utiliser le mot-clé new  et donner la taille du tableau (le nombre d’éléments). Les éléments sont indicés à partir de 0 (et les indices sont obligatoirement des entiers … sinon pour un système ‘clé-valeur’ il faut choisir une Map).
    ti = new int [4]; //les éléments sont : ti[0], .. , ti[3]
  3. initialisation : remplir le tableau cellule. Exemple 2 cellules :  ti[0] = -17;  ti[1] = ti.length;

Bien entendu, on peut regrouper ces étapes en une seule instruction :

  • déclaration + allocation + initialisation : voici 2 exemples avec les crochets placés avant ou après :
    int ti [] = { -17, 4, 3, -6};
    char[] tc = {'a','b','c'};
  • déclaration + allocation : exemple :  char tc[] = new char [3];

Quelques précisions bien utiles :

  • length : donne le nombre d’éléments du tableau.  Ex :  int n = ti.length; donne n = 4. Donc pour faire une boucle sur un tableau, on utilise toujours length :
    int tab [] = { -17, 4, 3, -6};
    for (int i=0 ; i < tab.length ; i++) //boucle sur tout le tableau
        System.out.println("L'élément n°" + i + " est " + tab [i]);
  • Affichage d’un tableau de caractères : System.out.println("tableau:" + String.valueOf(tc));

Ja_ArrayEx2Tableau[ ] [ ] (à 2 dimensions)

Un tableau à 2 dimensions est en réalité un tableau de tableau ! On utilise des doubles crochets [][] . On retrouve les mêmes 3 étapes :

  • déclaration du tableau :   les doubles crochets [] peuvent être placés avant ou après le nom du tableau :  int t [][];
  • allocation mémoire : il faut utiliser le mot-clé new  et donner la taille du tableau (le nombre d’éléments). Les éléments sont indicés à partir de 0 : t = new int [2][3];
  • initialisation : remplir le tableau : t = {{1, 2, 3} , {4, 5, 6}};

=Ja_tableau2dimensions>  t[i] désigne le i-ème tableau à 1 dimension d’entiers (sachant le 1er indice est 0) , donc :
t[0] = {1, 2, 3};  t[1] = {4, 5, 6};
t[0][0] = 1;       t[1][1] = 5;

On peut regrouper ces 3 étapes en une seule instruction :

  • déclaration + allocation + initialisation :  int t [][] = {{1, 2, 3} , {4, 5, 6}};
  • déclaration + allocation :  int t[][] = new int [2][3];
  • initialiser le tableau ligne par ligne :
    int t[][] = new int [2][];
    t[0] = new int[] {1, 2, 3};
    t[1] = new int[] {4, 5, 6};

Il est possible d’allouer les dimensions séparément à condition de commencer par la gauche :

int[][] matrice = new int[5][]; 
int[][] matrice = new int[][5]; // Erreur.

outils des tableaux

  • int n = tab.length;  pour connaitre la taille du tableau tab.
  • Arrays.sort(tab);   pour trier le tableau tab dans l’ordre croissant.
  • for (int n : tab) System.out.println(n);   pour parcourir le tableau tab (à 1 dimension).
  • int i = Arrays.asList(tab).indexOf("Valet");  pour connaître l’index de l’élément « Valet » dans le tableau tab. Attention : tab ne doit pas contenir de types primaires (int, char, …) mais des objets (String, Integer, …) car le tableau est converti en liste et une liste n’accepte pas les types primaires.
  • Pour parcourir un tableau à 2 dimensions :
    int tab[][] = { {1, 2, 3}, {4, 5, 6} };  
    for(int ligne[] : tab) { 
        for(int element : ligne) { 
            System.out.println("Item : " + element); 
        } 
    }

Tableau de JButton

JButton[] tabBtn = new JButton[9];

for (int i = 0; i < 9; i++) { // boucle créant 9 boutons
  final int i2 = i; //pour utiliser i ds ActionPerformed par variable finale
  tabBtn[i] = new JButton();
  tabBtn[i].setBounds(100 + 49 *(i%3), 100 + 49 * i/3, 50, 50);
  getContentPane().add(tabBtn[i]);
  tabBtn[i].addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent arg0) {
      //faire différentes choses puis désactivation du bouton
      System.out.println("Bouton qui a cliqué : i2 = "+i2);
      tabBtn[i2].setEnabled(false);
  });
}

ArrayList

Ja_ArrayList1ArrayList : 1 dimension

Un ArrayList ressemble à un tableau (à 1 dimension), à quelques différences près :

  • un tableau est de taille fixe (une taille maximale est donnée dans l’allocation mémoire) tandis qu’un ArrayList n’a pas de taille prédéfinie (l’allocation mémoire est dynamique).
  • un tableau ne contient qu’un seul type d’objet (int, String, ..) tandis qu’un ArrayList peut contenir n’importe quoi : caractère, entier, chaîne de caractères, nombre décimal …
  • on ne peut pas stocker des types primaires (int, char, float, double …)  dans un ArrayList, il faut utiliser des objets Integer, Character, Float, Double

Il faudra importer les librairies :  java.util.List et  java.util.ArrayList .

Les 2 étapes nécessaires sont :

  • déclaration de la liste :
    • List maListe;   pour déclarer une liste sans contenu.
    • List <String> maListe;   pour déclarer une liste de chaînes de caractère String.
    • List <Double> maListe;   pour déclarer une liste de nombres décimaux ‘double’.
      On remarque la majuscule à Double, car une liste ne peut pas contenir de type primaire comme double. Idem pour   List <Integer> maListe;   au lieu de ‘int’.
  • allocation :
    • maListe = new ArrayList();   pour créer la liste sans taille prédéfinie (et sans type de contenu)
      mais  ArrayList maListe = new ArrayList(); //mauvaise idée
    • maListe = new ArrayList<String>();  pour créer la liste de String … sans taille prédéfinie.

On peut regrouper ces 2 étapes en une seule instruction :

•  déclaration + allocation :   List <String> maListe = new ArrayList<String>();
•  initialisation d’Arraylist :  uniquement avec la méthode  add().

Exemple

List maListe = new ArrayList();
maListe.add('d'); //un caractère (char)
maListe.add("Une chaîne de caractères !");
maListe.add(12.20f); //un décimal (float)
maListe.add(1,101); //insère à l'index 1 l'entier '101'
        
for(int i = 0; i < maListe.size(); i++) {
  System.out.println("index " + i + " = " + maListe.get(i));
}

Ja_ArrayListConsole

outils des ArrayList

  • maListe.add('d');  pour ajouter un élément à la fin de la liste. [A cette occasion, un int est converti en Integer, un double en Double … ]
  • maListe.add(5,'d');  pour ajouter l’élément ‘d’ en index 5.
  • maListe.remove(5);  supprime l’élément qui est en index 5.
  • maListe.remove('d');  supprime la première occurrence de l’élément ‘d’ . Si l’élément est présent plusieurs fois, il n’est enlevé qu’une seule fois. Le contenu des cases est décalé, et la longueur de l’ArrayList diminue de 1. Si l’élément n’est pas présent, la liste n’est pas modifiée.
  • int n = maListe.size();    donne la longueur de l’ArrayList.
  • maListe.isEmpty()   renvoie true si une liste est vide … ou false sinon.
  • maListe.get(5)    renvoie l’élément de la case numéro 5 (sachant que le 1er index est 0). [A cette occasion un Integer est converti en int, un Double en double … ]
  • maListe.set(5,'d');   remplace l’ancienne valeur de la case 5 par ‘d’. Bien sûr, l’index doit être strictement inférieure à size().
  • maListe.contains('d')    renvoie true si la liste contient la valeur ‘d’ … et false sinon.
  • maListe.indexOf('d')   renvoie l’index de la 1ère occurrence de l’élément ‘d’ dans la liste. Et renvoie -1 s’il n’y apparaît pas.
  • maListe.lastIndexOf('d')   renvoie l’index de la dernière occurrence de l’élément ‘d’ dans la liste. Et renvoie -1 s’il n’y apparaît pas.
  • maListe.clear();   vide la liste.
  • maListe.addAll(autreListe);  ajoute tous les éléments de autreListe à la fin de maListe.
  • maListe.retainAll(autreListe);    enlève tous les éléments de maListe qui ne sont pas dans autreListe.
  • maListe.removeAll(autreListe);  enlève tous les éléments de maListe qui sont dans autreListe => il ne reste plus d’élément de autreListe dans maListe.
  • Collections.sort(maListe);  pour trier la liste maListe dans l’ordre croissant (si les éléments dans la liste sont de type Comparable : int, String, Date … ou d’une classe implémentant Comparable).
  • Collections.sort(maListe, Collections.reverseOrder());  idem dans l’ordre décroissant
  • System.out.println("liste : " + maListe);  affiche dans la console la liste des éléments entre crochets.
  • for (int n : maListe) { System.out.println(n); }  pour lister les éléments de la liste maListe.

Lister avec un itérateur :

Iterator itr=maListe.iterator();//un itérateur sur l'arraylist
while(itr.hasNext()){  
  System.out.println(itr.next());  
}

ArrayList d’ArrayList : 2 D

On ne peut pas créer de tableau 2D d’Arraylist mais on peut créer un ArrayList de ArrayList ArrayList<ArrayList<String>> pour obtenir 2 dimensions.

NB : Si on souhaite absolument faire un tableau contenant un Arraylist de type bien défini (String ou Integer …) alors une solution consiste à écrire une classe dérivant de ArrayList<String> (ou ArrayList<Integer> …) puis créer un tableau d’objets de cette sous-classe.

méthodes (fonctions)

Pour changer l’apparence d’un objet, il existe des fonctions (appelées des « méthodes » en java) qui sont propres au type d’objet (c’est-à-dire sa classe). Par exemple :

  • getText()  pour récupérer le contenu du champ de texte (JTextField) :  String texte = champDeTexte.getText();
  • setText() pour mettre un texte sur un objet : champDeTexte.setText("Hi");

Exemple : Ainsi pour récupérer le nom entré dans le champ de texte JTextField et le mettre dans l’étiquette JLabel :

JTextField champDeTexte = new JTextField(); // création des variables
JLabel etiquette = new JLabel();

String texte = "Bonjour "+champDeTexte.getText()+" !"; //récupère le texte et rajoute Bonjour
etiquette.setText(texte); //met le texte dans l'étiquette

Javadoc
Les méthodes d’un JTextField : setText() ; getText() ; setFont() ; getColor() ; setBounds() ; setBackground() … Pour la liste complète, taper dans un moteur de recherche « javadoc jtextfield »
Exemple : changer la couleur de fond :    getContentPane().setBackground(new Color(200,90,200));

Les accesseurs (ou getters) commencent par get
Les mutateurs (ou setters) commencent par set.

Les  tests :  if , switch case

if(  ){..} else {..}

Test  « Si … Alors … »               :   if  (test ) { instruction 1 ;}
Test « Si … Alors … Sinon … » : if  (test){ instruction 1 ;} else {instruction 2 ; }

Attention : Il n’y a pas de point-virgule après le  if(test). Les accolades sont nécessaires que s’il y a un bloc d’instructions.
affectation conditionnelle : Elle est difficile à lire (test) ? (valeur si oui) : (valeur si non)
c = a == 0 ? b : a+1 ;   Si le test a == 0 est true l’opérateur renvoie la 1ère valeur (donc c = b), sinon c = a+1.

switch( … ) case … break

switch équivaut à une série de if, il permet de comparer avec un grand nombre de valeurs, mais uniquement de type byte, char, int ou short.

Le switch teste chaque valeur (dans l’ordre) puis exécute le code correspondant jusqu’à l’instruction break (qui le fait sortir du switch).

switch (i) {
case 0:
    System.out.print ("i égale 0");
    break;
case 1:
    System.out.print ("i égale 1");
    break;
default:
    System.out.print ("i < 0 ou i > 1 ");
}

Les  boucles : for, while, do while

for( ; ; ){..} : boucle  itérative  avec  compteur

La boucle « Pour » contient un compteur i. Le plus souvent i est incrémenté de 1 à chaque tour de boucle : i++  (équivalent à i=i+1) :

for (i=1; i<=max; i++) { instruction ; }      signifie « Pour i allant de 1 à max faire … »

for(int i=0; i<5; i++) {
    System.out.print(i+"   ");
}  //affiche : 0  1  2  3  4

En réalité, la forme générale est   for (expr1; expr2; expr3) { instruction ;} :

  • « expr1 » est exécutée à la première entrée dans la boucle : on initialise une ou plusieurs variables (la liste d’instructions séparées par des virgules).
  • « expr2 » est la condition de rebouclage  :  on y place la condition de non-sortie (test de l’itération).
  • « expr3 » est exécutée à la fin de l’itération : on y place une réactualisation des variables (ex : incrémentation / décrémentation de 1, de 2..)(liste d’instructions séparées par des virgules).

exemple :   lister un tableau d’entiers  :

boucle sur les indices boucle sur les éléments d’un ensemble
for (int i=0, n=tableau.length ; i<n ; i++) {
    System.out.println(tableau[i]);
}
for (int e : tableau){
    System.out.println(e);
}

while(){..} : boucle (test au début)  

while (condition) {instruction;}    signifie  Tant Que  (la condition est vérifiée) faire …

C’est la boucle « Tant Que » la condition est vraie, la boucle continue. Comme le test est placé en début de boucle, cela signifie que si le test est faux avant de rentrer dans la boucle, alors celle-ci n’est jamais exécutée.

exemple : le programme calcule la plus petite valeur de la somme S tel que S soit supérieure à 100 :

int u, S = u = 1;  //somme = Uo = 1
while (S < 100) {
  u = u*(u + 1); //Un+1 = Un(Un + 1)
  S = S + u;     // ou  S += u;
}
System.out.print("Somme = "+S+" \\ dernier terme = "+u);

do {..} while(): boucle (test à la fin)

do {instruction  ; }  while (condition) ;     signifie  « Faire  ….  Tant Que (la condition est vérifiée) « 

C’est une autre boucle « Tant Que » mais cette fois le test est effectué en fin de boucle donc :

la boucle est toujours effectuée au moins une fois !

Exemple : Trouver un entier mystère 12 de manière aléatoire (nb_aleatoire) en 8 coups maximum.

int i=10, nbr_mystere = 12;
do {
  nb_aleatoire = (int) Math.floor(16*Math.random());
  i--;
} while (i>1 && nbr_mystere != nbr_mystere);

 

break ou continue : arrête une boucle

break;  permet de sortir d’une boucle : for, while, do while ou switch.

continue;  permet de sauter une ou plusieurs valeurs d’une boucle sans mettre fin à la boucle, càd de passer à l’itération suivante (ou plus exactement à la condition de l’évaluation suivante).

for (int x=0; x<=3; x++) {
    if (x == 2) {
       System.out.println("x vaut 2, on passe au suivant (x=3)!");
       continue; 
    }
    System.out.println("quotient : "+1.0/(x-2)); //quotient en float
}

classe

class peut être précédé d’une étiquette de portée (d’encapsulation) :

  • public : le plus bas niveau de protection : tout utilisateur qui importe le package peut utiliser cette classe. Mais dans ce cas, cette classe doit être dans un fichier .java , à part, qui porte son nom.
  • private : seules des classes définies dans le même fichier peuvent utiliser cette classe.
  • pas d’étiquette : toutes les classes du package peuvent utiliser la classe (donc public au sein du package de la classe et private en dehors).

Attention :  Une classe public doit obligatoirement être codée dans un fichier .java qui porte son nom, en revanche on peut coder autant de classes « non-public » que l’on veut dans le même fichier.

ja_classePublicPrivee

extends SuperClasse : signifie dérivant d’une super classe, elle hérite de toutes ses méthodes et attributs (penser à placer l’instruction super(); dans le constructeur de la classe dérivée pour appeler le constructeur de la SuperClasse).

implements NomInterface : signifie que la classe implémente une interface (une classe dont il est impossible de créer une instance, une classe abstract).

final

classe final :  final class  signifie que cette classe ne peut pas être dérivée.

méthode final :  signifie que cette méthode ne peut pas être dérivée.

variable final :

  • Pour rendre accessible une variable locale :  Pour faire passer une variable locale dans une classe anonyme (comme un Listener), alors cette variable doit être final.
  • Pour déclarer une constante :  Seule une variable de type primaire peut être déclarée comme constante avec le mot final. Ainsi, elle ne peut plus changer de valeur une fois initialisée.  Par convention, son nom est en MAJUSCULE.
final float RACINE_DE_2 = 1.41415f; // le f signifie "en type float"

NB : Un objet ne peut pas être une constante car tout objet est déclaré par référence, ainsi le mot clé final ne figerait que la référence mais pas les champs d’objet : les contenus resteraient modifiables.

static

Une variable ou une méthode static est utilisable sans créer d’instance de la classe (sans créer d’objet).

variable static : Si une variable globale à la classe (un attribut) est utilisée dans une méthode statique (comme static void main qui doit toujours être static) alors cette variable doit être statique.

méthode static :   Exemple   sur  la  classe  Math  :  Supposons que nous voudrions créer une méthode qui calcule la valeur absolue de x, dans une class MaClassMath. Comme cette méthode se suffit à elle-même alors pourquoi devrait-on d’abord créer un objet de la classe MaClassMath pour pouvoir utiliser cette méthode ?
=> C’est pour cela que le mot static permet à une méthode de s’exécuter sans avoir à instancier la classe (càd créer d’objet). L’appel à une méthode statique se fait en utilisant le nom de la classe (au lieu du nom de l’objet).

public class MaClassMath {
   public static double abs(double x) { // retourne la valeur absolue     
      if (x >= 0) { return x; } else { return -x; }
   }
}

public class Test {
   public static void main (String args[]){
      double y = MaClassMath.abs(-5.78); /aucun objet n’est créé	  
   }
}

this

A l’intérieur d’une classe, on trouve parfois le mot-clé this : c’est une référence à l’objet. Il est souvent facultatif lorsqu’il est accompagné d’attribut ou méthode ( this.valeur=9; signifie valeur=9;). En revanche, il est utile lorsqu’il doit être seul comme   System.out.print(this);

public class Exemple {
  int valeur=0;
	
  void methode() {
	this.valeur = 9; // ou bien : valeur = 9;
  }
}

Eléments aléatoires

Il existe 2 librairies :

  • librairie Math : elle s’utilise directement (sans instanciation). Math.Random() donne un nombre décimale entre 0 et 1 (de type double). Puis au moyen de calculs, on peut faire évoluer la fourchette.
  • librairie Random : elle nécessite une instanciation. Puis elle permet d’obtenir un entier aléatoire dans la fourchette que l’on souhaite.

Float aléatoire

  • Math.Random() :  génère un nombre aléatoire entre 0 et 1 (plus précisément dans l’intervalle  [0 , 1[) de type float.

Si on veut changer les bornes de cet intervalle, il faut ruser :

  • Math.Random()*max : génère un nombre aléatoire de [0 , max[ de type float.
  • min + Math.Random()*(max - min) : génère un nombre aléatoire de [min , max[ de type float.
  • min + (int)(Math.random() * (max - min + 1)) : idem, avec la borne supérieure incluse, soit l’intervalle [min , max].

Entier aléatoire

Il faut 2 instructions :

  1. instancier la classe Random :  Random random = new Random();
  2. déterminer un entier de cette liste :
    • random.nextInt(max) : un entier de l’intervalle [0,max-1]
    • random.nextInt(min,max) : un entier de l’intervalle [min,max-1]

NB : il faudra importer la librairie Random avec Ctrl+Shift+O :   import java.util.Random;

Random random = new Random();
int i = random.nextInt(100); //entier entre 0 et 99
int j = random.nextInt(10,21); //entier entre 10 et 20 (inclus)

Les animations

Timer

Un Timer permet d’effectuer une action à intervalle régulier :

  • Il suffit d’enregistrer un ActionListener auprès de lui.
  • Puis de redessiner le composant de façon régulière.
Timer t = new Timer(20, new ActionListener() {
	public void actionPerformed(ActionEvent e) {
		composant.repaint();
	}
});

Attention : Si l’animation doit être lancée suite à l’action d’un bouton alors il faut utiliser un Thread …

Thread

Un thread est une portion de code capable de s’exécuter en Ja_multiThreadparallèle du programme principal, on obtient donc des actions simultanées évoluant de façon indépendante.  Un thread permet entre autre l’exécution d’une tâche de fond ou une animation ; on peut aussi utiliser plusieurs threads « en même temps ». Le programme principal est lui-même un thread.

Méthode à redéfinir :

  • run( )  :  exécutée une fois au chargement, mais cette méthode doit être lancée par start().

En fait, start() exécute run() sur une autre file d’exécution. (Si, par erreur, on appelle la méthode run() plutôt que start(), alors run() va s’exécuter dans le thread courant … car c’est start() qui crée une nouvelle file d’exécution.)

Utilité des threads : Comme java traite les événements un par un, alors on peut utiliser une thread pour forcer le passage à l’événement suivant. Par exemple : faire avancer une barre de progression, lancer une animation.

Thread pour déclencher une animation : Généralement, c’est un bouton qui lance l’animation (qui contient un Timer qui redessine un composant toutes les 20 ms) mais tant que l’animation (donc le Timer) n’a pas fini …. l’image n’est pas rafraîchie !!!  C’est un peu embêtant car cela signifie qu’on aura l’image qu’une fois l’animation terminée (donc on ne verra pas l’animation du tout). L’explication est la suivante : tant que le Listener du bouton n’a pas terminé son code (càd l’animation) alors les autres événements de la pile (les rafraîchissements) ne sont pas exécutés ! D’où l’intérêt d’utiliser plutôt un Thread.

On distingue 2 méthodes :

  • Utiliser une classe héritant de la classe Thread : class MaThread extends Thread, c’est plus simple mais moins polyvalent.
  • Implémenter l’interface Runnable : class PanelAnimation implements Runnable

Elles sont proposées sur l’exemple ci-après : une GUI avec un bouton qui lance une animation (une balle noire qui rebondit sur les bords d’un JPanel jaune). Avec la 1ère méthode, le projet contient 2 classes internes (un JPanel et un Thread), avec la 2ème méthode une seule classe (un JPanel implémentant Runnable).

Attention : une application qui lance des threads ne peut pas quitter normalement tant que tous ces threads sont encore actifs. Il faut donc les arrêter. Un type de thread particulier, appelé daemon ne présente pas cette contrainte.

En implémentant l’interface Runnable

Le projet contient qu’une classe interne qui hérite de JPanel et implémente l’interface Runnable ; c’est un JPanel jaune contenant un Thread qui bouge la balle toutes les 10 ms.

La GUI possède 2 boutons Go / Stop pour lancer ou arrêter l’animation sur une 2ème file d’exécution (un Thread) afin de permettre au programme principal (la GUI) de fonctionner en même temps.

La variable volatile est le thread lui-même. Volatile signifie que toute modification de cette variable est visible par les autres threads.

Départ et Fin

public class FenetreThread extends JFrame {
    private JButton btnStart, btnStop;
    private PanelAnimation panel;
     
    ///// --- classe interne : un JPanel avec un Thread intégré (implements Runnable)
    class PanelAnimation extends JPanel implements Runnable {
        boolean right, down;
        int X,Y;
        private volatile Thread thread;
         
        PanelAnimation() {
            right = down = true;
            X = Y = 0;
        }     

        public void demarrer() {
            thread = new Thread(this); // crée un thread
            thread.start(); //et lance run() [dans une 2e file d'exécution]
        }
        
        public void arreter() {
            thread = null; //supprime le thread.
        }

        public void run() {
            Thread threadEnCours = Thread.currentThread();
            while (thread == threadEnCours) { //insère des pauses de 10ms
                try {Thread.sleep(10);} catch (InterruptedException e){}
                moveIt();
                repaint();
            }
        }
         
        public void paintComponent(Graphics g)  {
            super.paintComponent(g);
            setBackground(Color.YELLOW);
            g.setColor(Color.BLACK);
            g.fillOval(X, Y, 10, 10);
        }
 
        private void moveIt() { //calcul du déplacement
            if (X >= this.getWidth()-10){right = false; }
            if (X <= 0)  {right = true;  }
            if (Y >= this.getHeight()-10){down = false; }
            if (Y <= 0) { down = true;  }
            if (down) { Y++; }  else {Y--;}
            if (right){ X++; }  else {X--;}
        }
    } // fin de class PanelAnimation
       
 
 
    public FenetreThread() { /// constructeur de la classe principale
    /* contruction de la GUI : panel, btnStart, btnStop */
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(330, 350);
        setLocationRelativeTo(null);
        getContentPane().setLayout(null);

        panel = new PanelAnimation();
        panel.setBounds(20, 80, 260, 200);
        getContentPane().add(panel);
          
        btnStart = new JButton("Go !");
        btnStart.setEnabled(true);
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                panel.demarrer();  panel.demarrer();
                btnStart.setEnabled(false);
                btnStop.setEnabled(true);
            }
        });
        btnStart.setBounds(0, 0, 99, 59);
        getContentPane().add(btnStart);
                
        btnStop = new JButton("Stop");
        btnStop.setEnabled(false);
        btnStop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                panel.arreter();
                btnStop.setEnabled(false);
                btnStart.setEnabled(true);
            }
        });
        btnStop.setBounds( , , , ); getContentPane().add(btnStop);

        setVisible (true); 
    } /////////////////////////////////////////////////////////////////
 
    public static void main(String[] args) {
        new FenetreThread();
    }
}

Départ, Fin et Pause

Ja_ThreadRunnablePauseEnfin, il est également possible de mettre un thread en pause, puis le faire reprendre.

C’est un flag (un booléen) qui indique l’état de pause du thread et on utilise les méthodes :

  • wait()  :  pour mettre le thread en pause. Cette méthode doit être mise dans un try catch (car elle peut provoquer une InterruptedException), il faut la mettre dans le même try/catch que sleep() . L’ideal est de le mettre juste après le sleep mais avant le repaint() afin que la fenêtre soit immédiatement repeinte lorsqu’on réveillera le thread.
  • notify() :  pour reprendre (càd réveiller un thread qui était en pause).

De plus, wait() et notify() doivent être mis dans des blocs synchronized, afin de s’assurer qu’un thread endormi ne rate pas un notify() et reste endormi indéfiniment. Effectivement :

Si une méthode synchronized est déjà en cours d’exécution, alors les threads qui en auraient également besoin doivent attendre leur tour.

De même, On ne doit pas stopper un thread qui est en état de pause (il resterait endormi indéfiniment), il faut d’abord le réveiller (avec notify() ) puis le stopper.

public class FenetreThread extends JFrame {
    private JButton btnStart, btnStop, btnPause;
    private PanelAnimation panel;
     
    ///// --- classe interne : JPanel + Thread intégré (implements Runnable)
    class PanelAnimation extends JPanel implements Runnable { //classe interne
        boolean right, down, enPause;
        int X,Y;
        private volatile Thread thread = null;  // volatile
         
        PanelAnimation() {
            right = down = true;
            X = Y = 0;
        }     

        public void demarrer() {
        	thread = new Thread(this); // crée un thread
        	thread.start(); //et lance run() [dans une 2e file d'exécution]
        }
        
        public synchronized void arreter() { //avec synchronized (car notify())
            thread = null;
            notify();
        }
        
        public synchronized void suspendre() {  // avec synchronized (car notify())
	        	enPause = !enPause; //inverse l'état
	            if (!enPause) notify(); //réveille la thread
        }     

        public void run() {
            Thread threadEnCours = Thread.currentThread();
            enPause = false;
            while (thread == threadEnCours) {
                try {
                	Thread.sleep(10); //pause de 10ms
                    synchronized(this) {
                        while (enPause && thread == threadEnCours)
                            wait();
                    }
                } catch (InterruptedException e){}
                moveIt();
                repaint();
            }
        }
                
        public void paintComponent(Graphics g)  {
            super.paintComponent(g);
            setBackground(Color.YELLOW);
            g.setColor(Color.BLACK);
            g.fillOval(X, Y, 10, 10);
        }
 
        private void moveIt() { //calcul du déplacement
            if (X >= this.getWidth()-10){right = false; }
            if (X <= 0)  {right = true;  }
            if (Y >= this.getHeight()-10){down = false; }
            if (Y <= 0) { down = true;  }
            if (down) { Y++; }  else {Y--;}
            if (right){ X++; }  else {X--;}
        }
    } // fin de class PanelAnimation
       
 
 
    ///////////////////////////////////////////////////////////////////
    public FenetreThread() { /// constructeur de la classe principale
        /* contruction de la GUI : panel, btnStart, btnStop */
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(330, 350);
        setLocationRelativeTo(null);
        getContentPane().setLayout(null);

        panel = new PanelAnimation();
        panel.setBounds(20, 80, 260, 200);
        getContentPane().add(panel);
         
        btnStart = new JButton("Go !");
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                panel.demarrer();  panel.demarrer();
                btnStart.setEnabled(false);
                btnStop.setEnabled(true);
            }
        });
        btnStart.setBounds(0, 0, 99, 59);
        getContentPane().add(btnStart);
        
        btnStop = new JButton("Stop");
        btnStop.setEnabled(false);
        btnStop.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		panel.arreter();
        		btnStop.setEnabled(false);
        		btnStart.setEnabled(true);
        	}
        });
        btnStop.setBounds( , , , ); getContentPane().add(btnStop);
       
        btnPause = new JButton("Pause");
        btnPause.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		panel.suspendre();
        	}
        });
        btnPause.setBounds( , , , ); getContentPane().add(btnPause);

        setVisible (true);       
    } /////////////////////////////////////////////////////////////////
 
    public static void main(String[] args) {
        new FenetreThread();
    }
}

classe interne héritant de Thread

Le projet contient 2 classes internes :

  • class PanelAnimation extends JPanel : c’est un JPanel jaune contenant une balle noire en (X,Y).
  • class MaThread extends Thread : un Thread qui change les coordonnées (X,Y) de la balle puis rafraîchit le dessin du JPanel toutes les 10 ms.

Si on veut rassembler ces 2 classes en une seule alors il faut savoir que ce n’est pas possible : une classe ne peut pas hériter de JPanel et Thread en même temps … La solution consiste alors à implémenter l’interface Runnable.

Une classe ne peut hériter que d’une classe (Java ne permet pas l’héritage multiple).
Mais une classe peut implémenter une ou plusieurs interfaces (en même temps).

Juste un départ d’animation

Ja_ThreadInterneStart         Ja_ThreadInterneStart0

La GUI ne possède qu’un bouton Go qui lance l’animation (qui contient une longue boucle). Cette animation s’arrête à la fin de la boucle.

Cette animation est lancée sur une 2ème file d’exécution (un Thread) donc le programme principal (la GUI) fonctionne en même temps.

public class FenetreThread extends JFrame {
    private JButton btnStart;
    private PanelAnimation panel;
    MaThread thread; 
    
    ///// ----- classe interne : un JPanel avec une balle(X,Y) 
    class PanelAnimation extends JPanel { //classe interne
        boolean right, down;
        int X,Y;
        
        PanelAnimation() {
            right = down = true;
            X = Y = 0;
        }
        
        public void paintComponent(Graphics g)  {
            super.paintComponent(g);
            setBackground(Color.YELLOW);
            g.setColor(Color.BLACK);
            g.fillOval(X, Y, 10, 10);
        }

        private void moveIt() { //calcul du déplacement
            if (X >= this.getWidth()-10){right = false; }
            if (X <= 0)  {right = true;  }
            if (Y >= this.getHeight()-10){down = false; }
            if (Y <= 0) { down = true;  }
            if (down) { Y++; }  else {Y--;}
            if (right){ X++; }  else {X--;}
        }
    } // fin de class PanelAnimation
      
    ///// ----- classe interne : thread sur un PanelAnimation(JPanel)
    public class MaThread extends Thread { //classe interne
        PanelAnimation panel;
        
        MaThread(PanelAnimation panel0) {
            panel = panel0;
        }
    
        public void run() {
            for (int i=0 ; i<1000 ; i++) { //longue boucle
                panel.moveIt();  // Change X et Y
                panel.repaint(); // lance paintComponent()          
                try { sleep(10); } //petite pause = 10 ms                           
                catch (InterruptedException ex) { } 
            }
        }           
    }  // fin de class MaThread

    ///////////////////////////////////////////////////////////////////
    public FenetreThread() { /// constructeur de la classe principale
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(330, 350);
        setLocationRelativeTo(null);
        getContentPane().setLayout(null);

        panel = new PanelAnimation();
        panel.setBounds(20, 80, 260, 200);
        getContentPane().add(panel);
        
        btnStart = new JButton("Go !");
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                thread = new MaThread(panelAnimation);
                thread.start(); // start() lance run()
                btnStart.setEnabled(false);
            }
        });
        btnStart.setBounds(0, 0, 99, 59);
        getContentPane().add(btnStart);
        
        setVisible (true);
    } /////////////////////////////////////////////////////////////////

    public static void main(String[] args) {
        new FenetreThread();
    }
}

Daemon

Un daemon est un thread qui s’effectue une tâche de fond, sans interaction avec l’utilisateur : une musique de fond, un fond d’écran animé, un serveur de mail … Un daemon se stoppe tout seul quand les autres activités du programme sont finies.

Dans l’exemple précédent, pour mettre l’animation en daemon : on remplace la boucle  for (int i = 0 ; i < 1000 ; i++) { … } par une boucle infinie while (true) { … } et on met le thread en daemon juste avant le start().

public void run() {
    while (true) { //boucle infinie
        panel.moveIt();  
        panel.repaint();      
        try { sleep(10); }                     
        catch (InterruptedException ex) { }           
    }
}         
//////////////////////////////////////////////////
btnStart.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent arg0) {
        thread = new MaThread(panelAnimation);
        thread.setDaemon(true); // thread mise en tâche de fond
        thread.start();
        btnStart.setEnabled(false);
    }
});

Départ et Fin

La GUI possède 2 boutons Go / Stop pour lancer ou arrêter l’animation sur une 2ème file d’exécution (un Thread) afin de permettre au programme principal (la GUI) de fonctionner en même temps.

Pour arrêter le Thread utilise un flag (un booléen) déclaré comme volatile afin que toute modification de cette variable soit visible par les autres threads (car une variable volatile n’est pas stockée dans le cache du thread).

public class FenetreThread extends JFrame {
    private JButton btnStart, btnStop;
    private PanelAnimation panel;
    MaThread thread; 
     
    class PanelAnimation extends JPanel { 
        /* le panel jaune (classe interne) */
    } 
       
    public class MaThread extends Thread { 
        /* Thread (classe interne) avec un boolean volatile */
        private volatile boolean finir;
        PanelAnimation panel;
         
        MaThread(PanelAnimation panel0) {
            panel = panel0;
            finir = false;         
        }
     
        public void run() {
            while(!finir) {
                panel.moveIt();
                panel.repaint();       
                try { sleep(10); }                       
                catch (InterruptedException ex) { }
            }
        }
        
        public void arreter() {
            finir = true;
        }
    }  // fin de class MaThread
 
    ///////////////////////////////////////////////////////////////////
    public FenetreThread() { /// constructeur de la classe principale
    /* contruction de la GUI : panel, btnStart, btnStop */
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(330, 350);
        setLocationRelativeTo(null);
        getContentPane().setLayout(null);

        panel = new PanelAnimation();
        panel.setBounds(20, 80, 260, 200);
        getContentPane().add(panel);
          
        btnStart = new JButton("Go !");
        btnStart.setEnabled(true);
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                thread = new MaThread(panel);
                thread.start(); // lance run()
                btnStart.setEnabled(false);
                btnStop.setEnabled(true);
            }
        });
        btnStart.setBounds(0, 0, 99, 59);
        getContentPane().add(btnStart);
        
        btnStop = new JButton("Stop");
        btnStop.setEnabled(false);
        btnStop.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                thread.arreter();
                btnStop.setEnabled(false);
                btnStart.setEnabled(true);
            }
        });
        btnStop.setBounds( , , , ); getContentPane().add(btnStop);

        setVisible (true);
    } /////////////////////////////////////////////////////////////////
 
    public static void main(String[] args) {
        new FenetreThread();
    }
}

Entrée / Sortie / Scanner / Flux / Requête

Sortie console

Pour écrire sur la console de Java : System.out.println("texte="+x+"texte");  .. pour le débogage.

Pour écrire dans une fenêtre alors il faut réaliser une JFrame (avec un JLabel) … bref une GUI.

Entrée clavier

Le plus naturel est de faire une GUI avec un champ de texte et de récupérer le contenu avec getText(). Cependant, il est possible d’ouvrir un scanner clavier.

La classe Scanner permet de lire et d’isoler dans la saisie : un entier, un mot, une ligne … au clavier (System.in) ou dans un fichier (FileReader).

import java.util.Scanner;  pour importer cette classe.

Attention : On ne peut pas faire plusieurs ouvertures et fermetures de Scanner !

une phrase

Scanner sc = new Scanner(System.in); //ouvre scanner clavier
String phrase = sc.nextLine();
sc.close(); //ferme le scanner
System.out.print("La phrase est : "+phrase);

un mot, un caractère

Le scanner enregistre la saisie et stocke la 1ère chaîne de caractère. Les séparateurs de mots par défaut sont : espace, tab, entrée.

Scanner sc = new Scanner(System.in); //ouvre scanner clavier
String mot = sc.next(); //renvoie 1er mot
sc.nextLine(); //vide le scanner de la fin de ligne
sc.close(); //ferme le scanner
System.out.print("Le mot est : "+ mot);

Pour modifier les séparateurs : sc.useDelimiter(";|\n");

Pour saisir un caractère : char c = sc.next().trim().charAt(0);

un entier, un float

Pour un entier, c’est un peu plus délicat car rien ne nous garantit que l’utilisateur va bien entrer un entier ! Alors il y a 2 solutions :

  1. on entoure la saisie d’un bloc try { } catch() {} pour attraper l’exception si la saisie n’est pas un entier.
    Scanner sc = new Scanner(System.in); //ouvre scanner clavier
    try {
       int i = sc.nextInt();  //Renvoie le prochain entier 
       System.out.print("L'entier = "+i);
     } catch (Exception e) //si pas d'entier reconnu
    sc.nextLine(); //vide la fin de ligne restée dans scanner
    sc.close(); //ferme le scanner
  2. on teste avant si la saisie est bien un entier avec if(sc.hasNextInt()){} :
    Scanner sc = new Scanner(System.in); //ouvre scanner clavier
    if(sc.hasNextInt()){
       int i = sc.nextInt();  //Renvoie le prochain entier 
       System.out.print("L'entier = "+i);
    }
    sc.nextLine(); //vide la fin de ligne restée dans scanner
    sc.close(); //ferme le scanner

Pour un float, c’est exactement pareil à condition de mettre : sc.nextFloat()  et   sc.hasNextFloat().

Scanner un String

On peut aussi utiliser la classe Scanner directement sur un String (au lieu de la saisie clavier System.in).

String s = "Hello World! 3 + 3.0 = 6 ";
Scanner sc = new Scanner(s); //met la chaîne s dans un scanner
while (sc.hasNext()) {
   // teste si le prochain mot est un entier, puis l'écrit.
   System.out.println(sc.hasNextInt()+" pour le mot" +sc.next());
}
sc.close(); //ferme le scanner

Le résultat est :
false  pour  Hello
false  pour  World!
true  pour  3
false  pour  +
false  pour   3.0
false   pour  =
true  pour  6

Flux / Fichier : lecture, écriture

On manipule des objets de classe File (fichiers et répertoires), FileReader, FileWriter … (uniquement pour les applications car les applets n’ont pas ces droits : question de sécurité).

Comme FileWriter, FileReader écrit/lit caractère par caractère, alors pour manipuler des lignes on utilise une autre classe BufferedReader, BufferedWriter, PrintWriter .. ou Scanner  puis on ferme le flux.

import java.io.*;  pour importer ces classes.

De plus, pour parer aux erreurs d’ouverture/écriture de fichier, on attrape l’exception en l’entourant d’un try {//ouverture & écriture sur fichier} catch (Exception e) {//afficher le code erreur e }

Lecture de fichier

Avec  BufferedReader :

try {//ouvre 1 flux d’entrée d’octet (ficher existant)
   FileReader fr = new FileReader("c:\\windows\\system.ini");
   BufferedReader br = new BufferedReader(fr);
   while (br.ready()) 
      { System.out.println(br.readLine()); }
   br.close(); // penser à fermer le fichier
} catch (Exception e){System.out.println("Erreur "+e);}

Ou avec Scanner :

try {//ouvre 1 flux d’entrée d’octet (ficher existant)
   FileReader fr = new FileReader("c:\\windows\\system.ini");
   Scanner sc = new Scanner(fr);
   while (sc.hasNextLine())
     { System.out.println(sc.nextLine()); }
   sc.close(); // fermer le scanner
} catch (Exception e){System.out.println("Erreur "+e);}

Pour lire le fichier en binaire (ça prend moins de place que les octets) alors  FileReader() devient  FileInputStream() .

Ecrire dans un fichier existant

Avec  BufferedWriter :

try { //ouvre 1 flux de sortie (sur un ficher existant)
     FileWriter fw=new FileWriter("c:\\essai.txt");
     BufferedWriter bw = new BufferedWriter(fw); 
     bw.write("Bonjour,"); 
     bw.newLine();
     bw.write("une ligne...");
     bw.close(); // penser à fermer le fichier
} catch (Exception e) { System.out.println("Erreur "+e);}

Ou avec PrintWriter :

try { //ouvre 1 flux de sortie (sur un ficher existant)
    FileWriter fw=new FileWriter("c:\\essai.txt");
    PrintWriter pw = new PrintWriter(fw);
    pw.println("Bonjour,");
    pw.print("une ligne...");
    pw.close(); // fermer le fichier
} catch (Exception e) { System.out.println("Erreur "+e);}

Pour écrire le fichier en binaire (prend moins de place que les octets) alors FileWriter() devient  FileOutputStream().

Requête Serveur + Parsing DOM

envoie de requête + réponse

Exemple sur une requête d’horaire du prochain bus String ligne à l’arrêt int stop.

Les imports : import java.io.*; import java.net.URL; import java.net.URLConnection;

try { // address = la requête complète à envoyer au serveur !!
    String address = "https://data.keolis-rennes.com/xml/?cmd=getbusnextdepartures&version=2.1&"
            +"key=XXXXXXXXXXXX&param[mode]=stopline&param[route][]="+ ligne
            + "&param[direction][]=0&param[stop][]="+ stop + "&param[route][]=" + ligne
            + "&param[direction][]=1&param[stop][]=" + stop + "";
    URL url = new URL(address);
    URLConnection yc = url.openConnection();
    String answer = "", temp = "";
    BufferedReader in = new BufferedReader(new InputStreamReader(
            yc.getInputStream()));
    while ((temp = in.readLine()) != null) {answer = answer + temp;}
    String reponseServer = answer;  // reponseServer = la réponse complète du serveur !
    in.close();
} catch (Exception e) {e.printStackTrace();}

Parser la réponse / node / DOM

Pour exploiter la réponse XML, il faut récupérer un ou plusieurs nœuds, appelés node … puis le contenu d’une balise ou les attributs d’une balise.

Les imports : import org.w3c.dom.*;  import javax.xml.parsers.*;


Pour récupérer le contenu d’une balise :
ex : <departure headsign='Champs Blancs'>2012-08-25T15:01:35+02:00</departure>
=> on veut obtenir le contenu donc   2012-08-25T15:01:35+02:00

NodeList departures = doc.getElementsByTagName("departure"); //liste des noeuds <departure>
Node departure = departures.item(0);  // le 1er noeud de cette liste (item n°0)
String HeureDepart = departure.getTextContent(); //contenu de la balise <departure> </departure>

Pour récupérer un attribut de balise :

// d'abord on transforme le 1er Node <data> en Element (item 0)
Element node = (Element) doc.getElementsByTagName("data").item(0);
NamedNodeMap attributes = node.getAttributes();  // liste des attributs de cette balise
Attr attr = (Attr) attributes.item(0);  // le 1er attribut de cette liste (item 0)
String HeureLocale = attr.getNodeValue(); // pour obtenir la valeur de cet attribut.

Exemple : extraire le contenu de toutes les balises <departure> contenues à l’intérieur d’une chaîne de type XML.

String xml = "<?xml version= '1.0' encoding= 'ISO-8859-1'?>" 
        + "<stopline>"
        + "<stop>856</stop><route>965</route><direction>0</direction>"
        + "<departures>"
        + "<departure accurate='1' headsign='Champs Blancs'>2012-08-25T15:01:35+02:00</departure>"
        + "<departure accurate='0' headsign='Champs Blancs'>2012-08-25T15:16:00+02:00</departure>"
        + "</departures>"
        + "</stopline>";  //Attention cet ex ne contient qu'une seule balise <stop>
                
try{
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));

    NodeList departures = doc.getElementsByTagName("departure");
    System.out.println("Nombre de departure = " + departures.getLength());
    for (int i = 0; i < departures.getLength(); i++){
        Node departure = departures.item(i);
        System.out.println(i + "° ) prochain départ : " + departure.getTextContent());
    }
} catch(Exception e){ e.printStackTrace(); }

Passage par valeur ou par référence

Passage par valeur :

Les arguments de type primaires (int, double, … ) sont en fait recopiées dans une variable locale. Par conséquent, le paramètre initial n’est pas modifié.

public class Exemple { 
   static void procedure(int i) {
	 i = i+2 ; //modif de i = paramètre = variable locale
	 System.out.println("DEDANS, i=" + i) ;
    }

   public static void main(String[ ] args) {  
	 int i = 0;
	 System.out.println("AVANT la procédure, i=" + i);
	 procedure(i);
	 System.out.println("APRES la procédure, i=" + i);
    }
} //////  Affichage :
//  AVANT la procédure, i=O
//  DEDANS, i=2
//  APRES la procédure, i=0

Passage par référence :

Pour les objets (et surtout les tableaux), ce n’est qu’une référence vers l’objet qui est copiée, ainsi les champs des tableaux restent modifiables !

Au cours de l’exécution du programme il n’y a qu’un seul tableau mais 2 références : a et t.

public class Exemple { 
   static void procedure(int[] t, String mot) {
	t[0] = t[0] + 2;//modification d'un champ du tableau t
	mot="deux"; //modification d'un String, donc localemt uniquemt
	System.out.println("DANS la procédure, t[0]="+t[0]+" et mot="+mot);
   }

   public static void main(String[ ] args) {  
	int[] a = {1,2,3} ;
	String mot="zéro";
	System.out.println("AVANT la procédure, a[0]="+a[0]+" et mot="+mot);
	procedure(a,mot);
	System.out.println("APRES la procédure, a[0]="+a[0]+" et mot="+mot) ;
	mot = "trois";
	System.out.println("Cette fois, mot="+mot);
    }
} //////  Affichage :
//  AVANT la procédure, a[0]=1 et mot=zéro
//  DANS la procédure, t[0]=3 et mot=deux
//  APRES la procédure, a[0]=3 et mot=zéro
//  Cette fois, mot=trois

Cas particulier de String : En fait, un String est le résultat de 2 étapes : la création d’un tableau de caractères puis la réunion des caractères du tableau. Ainsi un String n’est modifiable que localement car à l’extérieur on n’a pas accès au tableau qui l’a créé (donc impossible de changer une lettre …). La solution est d’utiliser  StringBuilder ou StringBuffer.

Opérations en binaire

Ces opérations sont faîtes sur les nombres convertis en binaire (et non sur l’écriture décimale). Cependant, le résultat est retranscrit dans le format d’origine.

opérateurs  bit-à-bit

Opérateur Dénomination Effet Syntaxe Résultat
& ET bit-à-bit Retourne 1 si les deux bits de même poids sont à 1 : c’est le principe du masque. 9 & 12
1001 & 1100
8
1000
> OU inclusif Retourne 1 si l’un ou l’autre des deux bits de même poids est à 1 (ou les deux) 9 | 12
1001 | 1100
13
1101
^ OU exclusif Retourne 1 si l’un des deux bits de même poids est à 1 (mais pas les deux) 9 ^ 12
1001 ^ 1100
5
0101

rotation  de  bit

Opérateur Dénomination Effet Syntaxe Résultat
<< Rotation à gauche Décale les bits vers la gauche (multiplie par 2 à chaque décalage). Les bits qui sortent à gauche sont perdus, tandis que des zéros sont insérés à droite 6 << 1
110 << 1
12
1100
>> Rotation à droite avec conservation du signe Décale les bits vers la droite (divise par 2 à chaque décalage). Les bits qui sortent à droite sont perdus, tandis que le bit non-nul de poids plus fort est recopié à gauche 6 >> 1
0110 >> 1
3
0011
>>> Rotation à droite avec remplissage de zéros Décale les bits vers la droite (divise par 2 à chaque décalage). Les zéros qui sortent à droite sont perdus, tandis que des zéros sont insérés à gauche 3 >>> 1
0011 >>> 1
1
0001

Exemple :  Extraire le  Rouge, le Vert, le Bleu et le Alpha (d’un code couleur en hexadécimal) :

int rgb = 0x11AA0055; // en hexadécimal (préfixe 0x) : Alpha-R-V-B

//pour obtenir "55" (le bleu) : on  masque le début du nombre
int b = (rgb & 0xFF); // bleu : (0x11AA0055 & 0x000000FF) = 0x00000055 = 0x55

//pour obtenir v="00" : on pousse de 8 bits (= 2 caractères hexadécimaux) 
//puis on  masque le début du nombre
int v = ((rgb >> 8) & 0xFF); //(rgb >> 8)=0x11AA00  puis (0x11AA00 & 0xFF)=0x00
int r = ((rgb >> 16) & 0xFF);//(rgb >> 16)= 0x11AA  puis  (0x11AA & 0xFF)= 0xAA
int a = ((rgb >> 24) & 0xFF);//(rgb >> 24) = 0x11   puis  ( 0x11 & 0xFF )= 0x11
System.out.print("Résultat : Alpha = "+a+"; R = "+r+"; V = "+v+"; B = "+b);

Faire un exécutable JAR

Le but est de créer un fichier exécutable de votre programme Java … que vous pourrez distribuer à tous vos amis !!! Effectivement, le fichier JAR est autonome (pas besoin d’Eclipse) car il ne fait appel qu’à la JVM (Java Virtual Machine) qui est déjà installée sur tous les ordinateurs.

  1. Clic droit sur le projet > Export…  puis choisir la rubrique Java > Runnable JAR file.
    Ja_JAR1      Ja_JAR2
  2. Dans le menu déroulant de ‘Launch configuration’ choisir le projet Java. Puis choisir un nom de fichier pour le JAR et un emplacement sur votre ordinateur.
    Ja_JAR3
  3. Accepter l’avertissement. Puis rendez-vous à l’emplacement du fichier JAR pour l’exécuter.
    Ja_JAR4    Ja_JAR5

0_ambulance  Le fichier JAR ne s’exécute pas : Si votre projet utilise une image (ou un fichier audio, ou un fichier ressource quelconque) alors il faut impérativement créer une classe ResourceLoader pour qu’il se charge correctement (suivre ce tutoriel).

Pou voir les messages d’erreurs, il faut exécuter le JAR dans la console de Windows :

  • taper cmd  ou chercher  invite de commandes.
  • taper   java -jar C:\Users\VotreNom\Documents\votreProjet.jar    pour exécuter le fichier jar (bien entendu vous mettrez l’emplacement de votre fichier jar).

0_ambulance  « java Exception has occured » sur un autre ordi : Elle est dûe à une différence dans les versions de Java (la version de la JVM qui exécute le JAR et celle du JRE qui a fait la compilation). La solution est de faire une compilation incluant les versions précédentes, dans Eclipse :

  1. Télécharger les JRE (ou JDK) de versions inférieures puis installer les JRE dans Eclipse :
    Window > Preferences > Java > Installed JREs => Search …
  2. Abaisser le niveau de compilation du projet :
    Clic droit sur le projet > Propriétés > Java Compiler
    => décocher « Use compliance from execution environmt » puis régler le « Compiler compliance level » sur une version inférieure.

________________________________________