Présentation

L’algorithme

Un algorithme est une suite d’instructions à appliquer à un ensemble fini de données. La traduction d’un algorithme en un langage de programmation s’appelle un programme.

Quel est le principe d’un algorithme ? Il utilise des données fournies par l’utilisateur (les entrées), réalise diverses opérations dessus (les traitements) et produit un ou plusieurs résultats (les sorties).

Principe de base :

Plusieurs exécutions d’un algorithme avec les mêmes données d’entrée fourniront toujours le même résultat (l’algorithme est déterministe).

Le programme

Des langages intermédiaires entre l’algorithme et le langage machine ont été développés. Ces langages, appelés langages de haut niveau, ont une grammaire et une syntaxe proches du programmeur. Ils utilisent des termes anglais. Il ne faut cependant pas oublier que l’ordinateur ne connaît que le langage machine. Des outils spéciaux, appelés compilateurs, sont donc chargés de transcrire automatiquement le langage de haut niveau en langage machine.

Le compilateur remplace les termes par d’autres (par exemple le terme multiplier par 001110). C’est une tâche purement mécanique, le compilateur n’a aucune idée de ce que représentent ces termes. Il réalise un travail syntaxique, pas sémantique. Ainsi, si vous écrivez « multiplie » ou « multiplier », il s’arrêtera, ne reconnaissant pas ce terme.
Les langages de hauts niveaux apportent donc plus de souplesse et de lisibilité, mais ils n’en demeurent pas moins sous la contrainte d’un formalisme strict.

Comment s’exécute un programme ? C’est très simple : il exécute la première instruction, puis la deuxième, la troisième et ainsi de suite jusqu’à la dernière. Le programme est alors terminé.

Les différents langages d’implémentation

Il existe plusieurs centaines de langages de programmation si on tient compte de toutes les variantes possibles d’un même langage. L’ordinateur ne comprend nativement qu’un seul langage, le langage machine. Voici divers langages :

assembleur x86 sous DOS
Cseg segment
assume cs:cseg, ds:cseg
org 100h
main proc
jmp debut
mess db ‘Hello world!$’
debut:
mov dx, offset mess
mov ah, 9
int 21h
ret
main endp
cseg ends
end main

shell Unix
echo "Hello world!"

En Basic originel
10 PRINT "Hello world!"
20 END

langage C
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello world!\n");
return 0;
}

langage C++
#include <iostream>
int main()
{
std::cout < "Hello world!" < std::endl;
return 0;
}

PHP
<?php
print ("Hello world!");
?>

Java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

Visual Basic
Sub Main()
MsgBox("Hello world!")
End Sub

En Pascal
program Bonjour;
begin
WriteLn(‘Hello world!’);
end.

Certains langages ont été développés pour être utilisés dans des domaines précis. D’autres langages, tels le Java, sont généralistes.

« Le but n’est pas que le programme fonctionne, mais qu’il fonctionne vite et bien. Le meilleur ordinateur au monde et le meilleur langage au monde ne vous y aideront pas »
S.Rohaut – Algorithmique

Certains langages ne sont pas compilés mais interprétés. Pour fonctionner ces programmes nécessitent un interpréteur qui est un autre programme. Il analyse la syntaxe et l’exécute au fur et à mesure. Un langage interprété sera plus lent qu’un langage compilé à cause de la conversion dynamique du programme. On peut citer le PHP.

D’autres utilisent une machine virtuelle. La machine virtuelle est un programme qui permet d’isoler l’application qu’il doit faire tourner du matériel et du système d’exploitation. Le programme conçu pour la machine virtuelle pourra donc fonctionner sur n’importe quel ordinateur. Le Java et le C# utilisent ce principe.

Les normes de développement

Il existe des conventions de codage pour la plupart des langages de programmation. Il existe des variantes d’un langage à l’autre mais les règles de présentation, les conventions de nommage et l’organisation du code sont communs.

Le langage Java

Créé en 1995 par Sun Microsystem et racheté par Oracle en 2009. Le langage le plus utilisé en entreprise depuis quelques années et dans les applications mobile grâce à Android.

Avantages

  • Populaire
  • Portabilité, indépendant de l’OS
  • Langage orienté objet
  • Langage de haut niveau
  • JDK et API tierces très riches
  • Application sécurisées
  • Compilé et multi tâches

Inconvénients

  • non adapté pour des exécutions rapides (plutôt le C ou le JavaScript dans ce cas)
  • interfaces web plus difficile à mettre en place
  • verbeux

Les métiers

 

Les variables

Un souci primordial lors de l’écriture d’un algorithme est sa lisibilité. Il sera lu et corrigé par différentes personnes, c’est pourquoi il est important de respecter la syntaxe et d’y ajouter le maximum de commentaires possibles.

Chaque donnée d’un programme a un nom que l’on appelle un identificateur. Il faut respecter certaines règles pour ce nom soit valide :

  • il est formé d’un seul mot ;
  • il ne peut contenir que des chiffres, des lettres non accentuées (syntaxe anglo-saxonne des compilateurs) et le caractère souligné ( _ ) ;
  • le premier caractère ne peut pas être un chiffre ;
  • il doit être explicite, très utile pour l’humain (ex : prix_ht plutôt que k) ;
  • il doit être unique.

L’espace est un séparateur de mot, il ne peut donc pas être utilisé dans l’identificateur. Le compilateur travaille mot après mot, il considère qu’un identificateur est terminé lorsqu’il rencontre un espace.

Une variable contient une valeur qui peut changer. Chaque variable doit avoir un nom (identifiant) et un type définissant les valeurs qu’elle peut prendre.

Si la variable age est de type entier, elle pourra valoir –9, 45, 987 mais pas 5.5 (réel) .
Les trois variables prix_ttc, taux_tva et prix_ht seront de type réel.
Que se passerait-il si on définissait prix_ttc comme un entier ?

Les types de données

Le type d’une donnée détermine les valeurs qu’elle peut prendre. Les principaux types sont entier, réel, caractère, chaîne de caractère (ou chaîne) et booléen. Il en existe d’autres.

Type Plage de valeurs Exemples de valeurs
Entier simple int -32768 +32767 -58, 0, 328
Entire long long -2147483648 +2147483647
Réel simple précision float -3.4*10~38 à -1.4*10~45

1.4*10~45 à 3.4*10~38

-58, 3.1415, -1.1
Réel double précision double -1.79*10~308 à -4.94*10~324

4.94*10~324 à 1.79*10~308

Caractère char 0-255 ‘c’, ‘7’, ‘ ‘
Chaîne String « oh la belle chaîne ! », «  »
Booléen booleen false – true vrai, faux

Les caractères et les chaînes

  • les caractères des identifiants : on les entoure d’apostrophes. Ainsi, c’est un identificateur, ‘c’ un caractère ;
  • les chaînes des identifiants : on les entoure de guillemets. « Bonjour maman », « maison » sont des chaînes.
  • Une chaîne de longueur 1 (ne contenant qu’un seul caractère) n’est pas assimilable à un caractère. Ainsi, « 7 », ‘7’ et 7 sont trois données de types différents et nullement interchangeables.

Les booléens

Ils permettent de réaliser des tests. Un booléen ne peut prendre que deux valeurs : soit true (vrai) ou false (faux)

La déclaration et l’affectation des variables

class Padawan {
    public static void main (String[] args){
        int age;
    }
}
class Padawan{
    public static void main (String[] args){
        double prixTTC;
        prixTTC= 3.14;
    }
}

Donner le type des variables :

class Test{
    public static void main (String[] args){

        age=20;
        i=0;
        i=1+1;
        j=i;
        k=«coucou»;
        h=k+k;
        majeur=(age>18);
    }
}

Le code Java suivant ne fonctionne pas, pourquoi ?

Le compilateur javac fournit :

Test2.java :5 :possible loss of precision
class Test2{
    public static void main (String[] args){

        int ia;
        double fa;
        fa=3.14;
        ia=3.14;
    }
}

Le transtypage

Le transtypage consiste à indiquer entre parenthèses avant la valeur à affecter le type final de celle-ci.

class Test {
    public static void main(String[] args) {
        int x;
        double y;
        x = 3.14;
        y = (int) 3.14;

    }
}

On peut aussi affecter une variable à une autre variable :

class Test2{
    public static void main (String[] args){
        int a;
        int b;
        a=3.14;
        b=a;
    }
}

L’affichage

class Padawan{
    public static void main (String[] args){

        double prixTTC;
        prixTTC= 3.14;
        System.out.println(prixTTC);
    }
}

Le caractère saut de ligne :

Le caractère de contrôle « \n » (new ligne, saut de ligne) permet d’aller à la ligne. Ce caractère a la particularité de ne pas avoir de représentation visuelle graphique. La fonction System.out.println inclus le ln pour le retour à la ligne automatiquement.

class Padawan{
    public static void main (String[] args){

        double prixTTC;
        prixTTC= 3.14;
        System.out.print("moi je suis sur");
        System.out.print("une ligne");
        System.out.println("alors que moi je suis sur");
        System.out.println("deux lignes");
        System.out.println("et /n moi?");
    }
}

Comme c’est un caractère, le saut de ligne peut très bien faire partie d’une chaîne. La chaîne sera alors coupée à l’affichage. Ce caractère de contrôle est issu du C.

Écrire le programme qui affiche le prix total ttc en fonction du prix ht, du taux de tva et de la quantité achetée ( on prendra des valeurs au hasard).

Saisir

import java.util.Scanner;
class Sawan{
    public static void main (String[] args){
        Scanner sc = new Scanner(System.in);
        System.out.println("Veuillez saisir un mot :");
        String str = sc.nextLine();
        System.out.println("Vous avez saisi : " + str);
    }
}

On peut utiliser sc.nextInt()pour des int par exemple.

import java.util.Scanner;
class Sawan{
    public static void main (String[] args){
        Scanner sc = new Scanner(System.in);
        System.out.println("Veuillez saisir un nombre :");
        int a = sc.nextInt();
        System.out.println("Vous avez saisi : " + a);
    }
}

Seules les variables de type de base (entier, réel, caractère, chaîne, booléen) peuvent être initialisées par l’utilisateur.

Écrire un programme qui initialise deux variables entières et qui affiche directement la somme de ces deux nombres. N’oubliez pas d’afficher un message à l’utilisateur pour qu’il sache quoi saisir.

 

Les structures conditionnelles

La conditionnelle

class Padawan {
    public static void main(String[] args) {
        if (x == 8) {
            System.out.println("le nombre vaut 8");
        }
    }
}

Le booléen est la condition de l’instruction si. C’est généralement une expression booléenne.

Les instructions composant le si peuvent elles-mêmes être des si :

if( qte>100){
        if( tauxTVA==0.196){
        prixTTC=prixTTC*0.9;
      }
 }
class Padawan{
    public static void main (String[] args){
        if(x>0){
            System.out.println(« x est positif»);
        }
        if( x<=0)
            System.out.println(« x est négatif ou nul»);
    }
}

Deviens :

class Padawan {
    public static void main(String[] args) {
        if (x > 0) {
            System.out.println("x est positif");
        } else {
            System.out.println("x est négatif ou nul");
        }
    }
}

Indiquer si un nombre est supérieur à 30.

L’entreprise accorde une remise de 10 % sur le prix ttc pour tout achat de plus de 100 pièces ; écrire le programme calculant le prix ttc en fonction de la quantité, du prix ht et du taux de tva.

L’alternative

class Padawan {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double prix;
        String categorie;
        categorie = sc.nextString("entrez la categorie");

        switch (categorie) {
case "orchestre":prix = 35;
            break;
case "corbeille" :prix = 28.5;
            break;
case "balcon":prix = 15;
            break;
            default:
                prix = 10;
                break;
        }
        System.out.println("le prix est de " + prix);
    }
}

Le code ne fonctionne pas, il faut remplacer les chaine par des entiers. La branche default (facultative) permet de regrouper toutes les valeurs qui n’ont pas été énumérées. Si la branche default n’est pas présente et qu’aucune liste ne contient la valeur de l’expression, default n’a aucun effet.

Une agence de voyage propose des réductions sur les billets d’avion de 50€ selon la catégorie de chacun de ses clients. Si les personnes sont dans la catégorie senior, ils ont 50% de réductions. Dans la catégorie nourrisson, le prix du billet est forfaitaire, il sera de 20 euros. Pour les enfants, le prix sera de 30% de celui d’origine.
Écrire le programme qui affiche le prix final pour un client.

 

Les boucles

Tant que

La boucle de type « Tant que » permet la répétition d’un bloc d’instruction tant que la condition testée est vérifiée.

class Padawan {
    public static void main(String[] args) {
        int i = 0;
        while (i <= 10) {
            System.out.println(i);
            i++;
        }
    }
}

 Répéter … Tant que

Attention : on boucle quand le test est vrai, on s’arrête quand il est faux.

class Padawan{
    public static void main (String[] args){
        Scanner sc=new Scanner(Sytem.in);
        double num,den;
        num=sc.nextDouble("entrez le numerateur");
        do{
            den=sc.nextDouble("entrez le denominateur");
        }while(den==0);
        System.out.println(num+ '/'+ den+" = "+num/den);
    }
}

Écrire un programme qui saisit deux entiers et qui incrémente de 1 le premier tant qu’il n’est pas supérieur au deuxième.

Pour

On doit utiliser pour lorsque le nombre d’itérations est connu.

class Padawan {
    public static void main(String[] args) {
        for (int indice = 1; indice <= 20; indice++) {
            System.out.print("*");
        }
    }
}

Afficher les nombres de 0 à 10 dans l’ordre décroissant :

class Padawan {
    public static void main(String[] args) {
        for (int indice = 10; indice >= 0; indice--) {
            System.out.print(indice);
        }
    }
}

Afficher les nombres pairs de 0 à 20 dans l’ordre décroissant

Que fait cette boucle ?

class Padawan {
    public static void main(String[] args) {
        for (int j = 0; j <= 10; j++) {
            System.out.println(2 * j);
        }
    }
}
  • Le pas (incrément) de la boucle est donc un entier quelconque, mais il est fixe.
  • Un pas de zéro n’est pas une bonne idée : la boucle ne s’arrêtera jamais.
  • Le pour étant une instruction comme une autre, le corps d’un pour peut très bien contenir un autre pour (ou toute autre boucle).

Afficher pour chaque nombre de 1 à 10 les nombres qui lui précédent .

Pour chaque

La boucle pour chaque permet de faire défiler une collection que nous verrons dans les chapitres suivants.

//declaration d’un tableau
double[] ar = {1.2, 3.0, 0.8};
int sum = 0;
for (double d : ar) {
sum += d;
}

Voici la même boucle avec la structure for classique

double[] ar = {1.2, 3.0, 0.8};
int sum = 0;
for (int i = 0; i < ar.length; i++) {
sum += ar[i];
}
  1. Écrire un programme qui saisit un entier positif.
  2. Écrire un programme qui affiche n fois ‘coucou’, l’entier n sera saisi par l’utilisateur.
  3. Écrire un programme qui saisit un nombre tant qu’il n’est pas égal à 10.
  4. Écrire un programme qui saisit un nombre tant qu’il n’est pas égal à 10 et affiche un message du style ‘ce nombre n’est pas bon’.

 

Les méthodes

Lorsqu’un problème programme devient complexe, on le décompose en plusieurs sous-problèmes (sous-programmes).

Intérêts

– Réutilisation de la même procédure plusieurs fois au cours d’un programme en faisant un simple appel.
– Résoudre un programme long et complexe en plusieurs procédures plus simples.
– Obtenir des procédures totalement indépendantes du programme principal.

Une fonction est une suite d’instructions qui permet d’obtenir un résultat (s’il n’y a pas de résultat, on met void).

void afficherA(){
        System.out.println(«A»);
}

int renvoyer10(){
    int i=10;
    return i;
}
  1. Écrire une fonction qui affiche cinq fois bonjour
  2. Écrire une fonction qui renvoie bonjour
  3. Écrire une fonction qui renvoie le carré de 23
  4. Écrire une fonction qui renvoie la somme des nombres de 8 à 20
  5. Écrire la fonction puissance qui renvoie un nombre x à la puissance y (x et y sont connus dans le programme principal).
  6. Écrire une fonction qui prend en paramètre deux chaine de caractère et renvoie la concaténation de ces chaines
  7. Écrire une fonction Multiplie qui prend en paramètre deux réels. Ainsi Multiplie(2,4) calculera 2*4

 

La Programmation objet

La classe

Une classe est définie par son nom, ses propriétés et ses fonctions. Les objets sont des instances de classe. Ils sont structurés par les propriétés définissant la classe. Ils peuvent exécuter les fonctions définies au sein de la classe.

Le nom de la classe commence toujours par une majuscule.
Les attributs ou propriétés sont : nom, annee_naissance et salaire.
Les fonctions sont affiche() et calcul_age().
Tout objet de la classe Personne est structuré par les trois propriétés précédentes. Et cet objet a à disposition les deux fonctions citées.

Exemple :

Soit p1 et p2 deux instances de la classe Personne, donc deux objets Personne.
P1 a pour nom Henri, pour anne_naissance 1980 et p2 a pour nom Duval et pour annee_naissance 1982. Le salaire du premier est de 1500 et du deuxième 2100.
La fonction affiche() permet à p1 d’afficher son propre contenu (idem pour p2). La fonction calcul_age() d’afficher leur propre âge.
On appelle aussi les propriétés d’une classe des variables d’instances et les fonctions des méthodes.
Le nom d’une classe doit toujours être le même que le nom du fichier java. Il faut toujours ajouter une classe principale qui va exécuter le programme. Elle contient au moins une méthode particulière, la méthode main.

class Personne {
    private String nom;
    private int annee_naissance;
    private int salaire;

    public Personne(String n, int a, int s) {
        this.nom = n;
        this.annee_naissance = a;
        this.salaire = s;
    }
}
public void affiche(){
        System.out.println(nom+" "+annee_naissance+" "+salaire);
        }

public void calcul_age(){
        int age=2011-annee_naissance;
        System.out.println("age = "+age);
}
        --------------------------------------------------------------------------------------------------------
public static void main(String args[]){
        Personne p1=new Personne("dupont",1950,1500);
        Personne p2=new Personne("mercier",1962,2300);
        System.out.println(p1.nom);
        p1.affiche();
        p2.affiche();
        p1.calcul_age();
        p2.calcul_age();
}

Modifier le programme précédent pour qu’il puisse créer deux autres objets p3 et p4.
Réaliser une classe Sandwich qui possède comme propriété trois ingrédients, un poids et un prix.

Le constructeur

La plupart des classes doivent être dotées d’une fonction particulière appelée constructeur. Cette fonction doit porter le nom de la classe. Elle doit être déclarée en public. Elle prend en paramètre les variables que l’on souhaite initialiser.

private String nom;
private int annee_naissance;
private int salaire;
public Personne(String n,int a,int s){
        this.nom=n;
        this.Annee_naissance=a;
        this.salaire=s;
}

Créer un objet correspondant à la classe Sandwich en utilisant le constructeur .
Réaliser une classe logement qui possède un nombre de pièce, une surface, une adresse, un prix.
Créer deux objets correspondant à la classe.

L’encapsulation

Encapsulation avec private et public

Pour que chaque objet soit responsable de son état interne, il faut protéger les objets des interventions extérieures. C’est ce qu’on désigne par l’encapsulation.
Ce sont les valeurs des modificateurs qui fixent le niveau de protection des données et des méthodes.
Le modificateur private devant la définition d’une propriété ou d’une méthode interdit à un objet appartenant à une autre classe d’utiliser directement la propriété ou la méthode.
Le modificateur public les rend utilisable par une autre classe.
Les éléments public sont visibles à l’extérieur, les éléments private sont réservés à un usage interne aux objets de la classe.

public class Personne {
    private String nom;
    private int anneeNaissance, salaire;

    public Personne(String n, int a, int s) {
        nom = n;
        anneeNaissance = a;
        salaire = s;
    }

    public String getNom() {
        return nom;
    }

    public int getSalaire() {
        return salaire;
    }
}

public class CentreAdministratif {
    public static void main(String args[]) {
        Personne p1 = new Personne("Dupuis", 1980, 1800);
        Personne p2 = new Personne("Mercier", 1988, 1700);


//erreur!!! private non accessible
        System.out.println(p1.nom);

//ok public accessible
        System.out.println(p1.getNom());

//erreur!!! private non accessible
        System.out.println(p1.salaire);

//ok public accessible
        System.out.println(p1.getSalaire());
    }
}

Les méthodes d’instance qui permettent d’accéder aux données privés sont appelées des accesseurs. Il existe aussi des méthodes d’instances qui permettent de modifier ces objets, ce sont des modificateurs.
En programmation objet, l’usage est d’utiliser get pour les accesseurs et set pour les modificateurs.

public class Personne{
    private String nom;
    private int annee_naissance, salaire;
    public Personne (String n, int a, int s){
        nom=n;
        anneeNaissance =a;
        salaire=s;
    }

    public String getNom(){
        return nom;
    }

    public int getSalaire(){
        return salaire;
    }

    public void setSalaire(int salaire){
        this.salaire=salaire;
    }

    public void setNom(String nomV){
        this.nom=nomV;
    }
}

public class CentreAdministratif{
    public static void main(String args[]){
        Personne p1= new Personne("Dupuis", 1980, 1800);
        Personne p2= new Personne("Mercier", 1988, 1700);

//erreur!!! private non accessible
        p1.nom="Harry";

//ok public accessible
        p1.setNom("Harry");

//erreur!!! private non accessible
        p2.salaire=1890;

//ok public accessible
        p2.setSalaire(1890);
    }
}

Réaliser une classe Etudiant qui possède un nom, un prénom, un numéro, une date de naissance et une adresse. Ces éléments sont protégés. On réalisera les accesseurs et les modificateurs nécessaires.
Créer 3 étudiants et modifier le nom du premier, afficher la date de naissance du deuxième, modifier le numéro du troisième tout en affichant son nom.

Implémenter une association en programmation objet

On doit définir une variable possede de type Voiture dans la classe Personne. Comme une personne possède ou non une voiture, c’est elle qui va acheter ou vendre son véhicule. La classe Personne doit donc implémenter deux méthodes, la méthode achat_voiture(v) et la methode vente_voiture(p)

class Voiture {
    private String marque, modele, numero;
    public Voiture(String m, String mod, String num) {
        this.marque = m;
        this.modele = mod;
        this.numero = num;
    }
    public String toString() {
        return marque + " " + modele + " " + numero;
    }
}


class Personne {
    private String nom;
    private Voiture possede;
    private double prixAchatVoiture;
    public Personne(String n) {
        nom = n;
        possede = null;
    }
    public String toString() {
        String r = nom + " proprietaire de ";
        if (possede != null) {
            r=r+possede.toString();
        } else {
            r=r + "rien";
        }
        return r;
    }
    public void achat_voiture(Voiture v, double prixAchatVoiture) {
        this.possede = v;
        this.prixAchatVoiture = prixAchatVoiture;
    }
    public void vente_voiture(Personne p) {
        p.achat_voiture(this.possede,100);
        this.possede = null;
        this.prixAchatVoiture = 0;
    }
}

public class Main {


        public static void main(String args[]) {
            Personne p1 = new Personne("Cartier");
            Personne p2 = new Personne("Perrin");
            System.out.println(p1);
            System.out.println(p2);


            Voiture v1 = new Voiture("Citroen", "205", "4567TR89");
            System.out.println(v1);


            p1.achat_voiture(v1,100);
            System.out.println(p1);


            p1.vente_voiture(p2);
            System.out.println(p1);
            System.out.println(p2);

    }
}


Créer une classe Propriétaire. Cette classe possède comme propriété un nom, et un logement.
Créer deux objets correspondant à la classe.
Le premier achète un logement t1. Il le vend au propriétaire p2.
Ecrire le code correspondant.

 

Variables locales et variables globales :

Si les instructions constituant la procédure utilisent des variables (indice de boucle par exemple), ce sont des variables locales à la procédure (c’est-à-dire qui ne sont connues, et qui ne peuvent donc être utilisées que dans la méthode). Les variables du programme principal sont dites variables globales au programme. Elles sont lisibles par l’ensemble du programme contrairement aux variables locales.

public class Exemple {
    //variables globales
    int i, j;

    int renvoyerInt(int a) {
//variables locales à la méthode renvoyerInt
        int k = 32;
//utilisation de i, variable globale
        i = a + 32;
        return k;
    }

    static void main(String args[]) {
        k = 8;
// erreur sur k, n’existe que dans renvoyerInt
        j = 12;
        int o = renvoyerInt(8);
// o n’est visible que dans main
    }
}

Écrire une méthode afficherPersonne qui prend en paramètre le prénom et affiche le nom et le prénom de la personne. Le nom est déclaré en variable globale.
Ecrire la fonction principale qui utilise votre methode.
Ecrire une fonction qui affiche la somme de trois nombres passés en paramètre.
Ecrire une fonction qui renvoie la soustraction de deux nombres
Ecrire une fonction qui ajoute 7 nombres saisis par l’utilisateur à un nombre passé en paramètre et le renvoie.

 

Les structures de données

Les tableaux à une dimension

On souhaite enregistrer le nom de chaque étudiant de la classe. Une solution est de créer une variable par étudiant.

String nom1 = "Jo";
String nom2 = "Daril";
String nom3 = "Dave";
String nom4 = "Harry";
String nom5 = "Doris";
...

Pour éviter d’avoir un grand nombre de variable, on peut regrouper celle-ci en une seule, un tableau. On le représente souvent comme une suite de cases contenant chacune une valeur.
On appelle indice le numéro d’une case du tableau. En programmation, la première case commence à l’indice 0.

Déclaration d’un tableau

String lesNoms[] = new String[15] ;
//ou
String[] lesNoms= new String[15] ;
//ou
String lesNoms[] = {"Jo","Daril",......} ;

Affectation d’un tableau

tab[0]=5;
tab[1]=sc.nextInt() ;
tab[2]= tab[0]+ tab[1];

Pour le compilateur, le tableau n’est qu’une suite de variables. Il ne sait pas ce qu’elles contiennent.

  1. Écrire une fonction demandant à l’utilisateur 10 entiers. Les sauvegarder dans un tableau.
  2. Écrire  une fonction qui affiche les valeurs du tableau.
  3. Écrire  une fonction qui affiche les valeurs du tableau du dernier indice au premier.
  4. Écrire  une fonction qui affiche uniquement les valeurs négatives du tableau.

 

Tableaux à deux dimensions

Quelle variable utiliser pour représenter les notes des étudiants de BTS SIO?  Nous allons utiliser un tableau qui contiendra les 8 notes.

int tbNotes[8] ;

La classe compte 18 étudiants . Comment faire pour gérer toutes les notes de tous les étudiants de la classe ? Une solution serait de déclarer 18 tableaux de notes (un par étudiant).

int tbNotes1[8] ;
int tbNotes2[8] ;
...

En regroupant les variables dans un tableau. Et bien, on va faire pareil que pour les noms, en regroupant les tableaux dans un tableau. Cela donne un tableau de tableaux, soit un tableau à deux dimensions.

int tbNotesEtudiants[][] = new int[18][8];

Il faut bien comprendre que cela correspond au tableau suivant :

  1. Déclarer un tableau qui permette d’enregistrer 2 notes pour 3 étudiants.
  2. Réaliser une fonction qui permette de demander à l’utilisateur ces notes pour les trois étudiants grâce à une boucle.
  3. Afficher la moyenne des notes pour l’ensemble des étudiants.
  4. Afficher la moyenne des notes pour l’étudiant 3.

 

La Collection ArrayList

Les collections fonctionnent comme des tableaux. Ils possèdent une différence importante, leur taille est dynamique. Dès que la collection est pleine, sa taille est doublée, triplée de façon automatique. En Java, il existe différentes collections qui servent à implémenter des tableaux dynamique comme ArrayList.

Pour la classe ArrayList, il existe des méthodes qui permettent de manipuler ses éléments.

  • add( Type t) pour ajouter un élément
  • set(int i, Type t) qui permet de modifier un élément à la ieme place
  • get(int i) qui permet d’obtenir un élément de la ieme case
  • remove(Type t) et RemoveElementAt(int i) qui permettent de supprimer un élément
  • size() qui renvoie la taille de la collection.
ArrayList<Fleur> collFleurs = new ArrayList();
collFleurs.add(new Fleur("orchidée"));
collFleurs.add(new Fleur("tulipe"));
collFleurs.add(new Fleur("coquelicot"));

for(Fleur f: collFleurs){ 
    System.out.println("ma fleur:"+ f.getNom());
}

/* Equivalent */
for(int i=0;i<collFleurs.size();i++){
 System.out.println("ma fleur:"+collFleurs.get(i).getNom()); 
}

L’affichage de tous les éléments d’une collection fonctionne sur le même principe qu’un tableau en Java.

  1. On souhaite sauvegarder le nom et le prénom des étudiants. Réaliser une classe Etudiant
  2. Réaliser une collection qui permette de sauvegarder les 15 étudiants de la classe.
  3. Ajouter les 15 étudiants.
  4. Afficher le nom de tous les étudiants de la classe.
  5. Supprimer le 4eme étudiant.

Les conventions de nommage et la documentation

Les packages

  • Tout en minuscule.
  • Utiliser seulement [a-z], [0-9] et le point ‘.’: Ne pas utiliser de tiret ‘-‘, d’underscore ‘_’, d’espace, ou d’autres caractères ($, *, accents, …).
  • tout package doit avoir comme root un des packages suivant: com, edu, gov, mil, net, org ou les deux lettres identifiants un pays (ISO Standard 3166, 1981).
com.monProjet
com.apple.quicktime.v2
edu.cmu.cs.bovik.cheese

Les classes

  • 1ère lettre en majuscule
  • Mélange de minuscule, majuscule avec la première lettre de chaque mot en majuscule
  • Donner des noms simples et descriptifs
  • Eviter les acronymes : hormis ceux commun (XML, URL, HTML, …)
  • N’utiliser que les lettres [a-z] et [A-Z] et [0-9] : Ne pas utiliser de tiret ‘-‘, d’underscore ‘_’, ou d’autres caractères ($, *, accents, …).

Variables

  • 1ère lettre en minuscule
  • Mélange de minuscule, majuscule avec la première lettre de chaque mot en majuscule
  • Donner des noms simples et descriptifs
  • Ne pas commencer les noms avec ‘$’ ou ‘_’ bien que ce soit possible.
  • Variable d’une seule lettre (pour un usage local)
  • N’utiliser que les lettres [a-z] et [A-Z] et [0-9] : Ne pas utiliser de tiret ‘-‘, d’underscore ‘_’, ou d’autres caractères ($, *, accents, …).

Constants

  • Tout en majuscule
  • Séparer les mots par underscore ‘_’
  • Donner des noms simples et descriptifs
  • N’utiliser que les lettres [A-Z], [0-9] et ‘_’ : Ne pas utiliser de tiret ‘-‘ ou d’autres caractères ($, *, accents, …).

Fichiers Jars

  • Tout en minuscule
  • Séparer les mots par un tiret ‘-‘
  • Utiliser seulement les lettres [a-z], [0-9] et ‘-‘ : Ne pas utiliser d’underscore ‘_’ ou d’autres caractères ($, accents, …).
gb-fwk-1.0.jar
gb-tools-1.0-beta-7.jar
js-1.5R4-RC3.jar

La documentation

On peut générer automatiquement des pages HTML correspondants à la documentation de notre code. Que ce soit en Java ou en PHP, il suffit d’utiliser les annotations.
En renseignant ces annotations, l’utilitaire Javadoc va réaliser des pages HTML. Il est nécessaire de mettre ces annotations dans des balises de commentaires un peu particulière, :

/**
Il faut respecter les deux **.
Exemple :
*/


/** Classe A
* @author 666
* @version 1.0
*/

public class A {
/** Donne le nombre d'instanciations */
public static int nb;
/**
* Un constructeur avec un entier
* en paramètre
* @param n un entier
*/
public A(int c) {
nb++;
}

/** Pour faire un essai
* @param c un caract&egrave;re
* @return la valeur enti&egrave;re de c
* @exception ClassCastException si bizarre
* @see B
* @see #faire(char c)
* @see B#action()
*/

public int faire(char c) throws ClassCastException {
if (c == 'a') throw new ClassCastException();
return (int)c;
}
}

Un ensemble de fichiers HTML a été créé accessibles à partir du fichier index.html.

Héritage et Polymorphisme

On peut hériter une classe d’une classe mère. La classe fille pourra utiliser les propriétés et méthodes de la classe mère comme ses propres propriétés. L’héritage permet de construire des hiérarchies de classe. En java, toutes les classes sont dérivées de la classe Object. Elles héritent par défaut de cette classe sans spécifier extends Objets. On ne peut hériter que d’une seule classe.

public class Client {

    private String nom;
    private String adresse;
    private double reduction;
    //constructeur
    public Client (String leNom){
        this.nom=leNom;
    }

    //accesseurs - modificateurs
    public String getNom (){
        return this.nom;
    }

    private String getAdresse (){
        return this.adresse;
    }

    protected double getReduction (){
        return this.reduction;
    }
}

En dehors de la classe, nous avons accès au constructeur et à getNom.

On hérite la classe Client

public class ClientParticulier extends Client {
    private String nom ;
    private String adresse ;
    private double reduction;
    private String prenom ;
    //constructeur
    public ClientParticulier (String unNom){
        super(unNom) ;
    }
    //accesseurs - modificateurs
    public String getPrenom (){
        return this.nom ;
    }
}

Le mot extends permet d’hériter de la classe Client. Il faut utiliser le mot clef super dans la classe fille pour faire appel au constructeur de la classe mère en lui passant les paramètres dans l’ordre

On peut donc accéder aux propriétés de la classe Client depuis un objet ClientParticulier

ClientParticulier z=new ClientParticulier(« monClient ») ;

Le client va ici posséder un nom, une adresse et une réduction et bien sûr son prénom.

Prenons comme exemple la classe Personne. Si on souhaite modéliser des clients et des fournisseurs. La classe Personne possède un nom, une adresse. La classe client possède un montant annuel d’achat, pourcentage de réduction et un éventuel nombre de point_fidelite. La classe fournisseur possède une catégorie, un délai de livraison, un compte pour le paiement des marchandises.

import java.io.*;

class Personne {
    private String nom;
    private String adresse;

    public Personne(String n, String a) {
        nom = n;
        adresse = a;
    }

    class Fournisseur extends Personne {
        private String categorie;
        private double delais_j;
        private int compte;

        public Fournisseur(String nn, String aa, String c, double d, int i) {
            super(nn, aa);
            this.categorie = c;
            this.delais_j = d;
            this.compte = i;
        }
    }

    class Client extends Personne {
        private double montant;
        private double reducation;
        private int point_f;

        public Client(String nn, String aa) {
            super(nn, aa);
        }
    }

    public class cliEtFour {
        public static void main() {
            Personne p = new Personne(" Harry", "12 rue de la printanière");
            Client k = new Client(" Watson", "15 rue de la printanière");
            Fournisseur f = new Fournisseur(" Walifi", "14 rue de la printanière", "details", 320.2, 4500);
        }
    }
}

Lors de la définition du constructeur d’un objet de la classe dérivée, il faut faire appel au constructeur de la classe de base avec l’instruction super.

Créer une classe gateau et une classe pain. Celles-ci héritent de la classe produit. Le produit possède un prix, une date de fabrication et une date de fin de vente. La classe gateau possède une taille correspondant au nombre de personne, un ingrédient de base. La classe pain possède un type de farine, un type classique ou special, un poids.

Les méthodes static et d’instance

Les méthodes static

Le modificateur static permet de définir une variable comme variable de classe. Une variable de classe est la même pour chaque instance d’un objet.

public class Chat{
    //variables static
    private static int numero=0;
    //variables d’instances
    int poids;
    Chat(int poids){
        this.poids = poids;
        numero++;
    }
}

Il peut aussi s’appliquer aux fonctions. La méthode est alors directement appelée par la classe sans nécessiter de déclaration d’objet

Math.pow() ;

On emploie ces méthodes lorsqu’elles n’ont pas de rapport direct avec les objets de la classe.

On souhaite réaliser un objet carte réseau. On sauvegardera le nombre de port, le débit, l’adresse MAC.
Toute les cartes proviennent du même constructeur donc le code est 089AAB. L’adresse MAC est constituée en premier lieu du code du constructeur puis d’un code générique que l’on mettra au hasard. Réaliser la classe et le constructeur. Attention, l’adresse commencera donc toujours par le même code.

Les méthodes d’instances

Les méthodes d’instances correspondent à celle que vous réalisez déjà. Il est nécessaire de déclarer un objet de la classe pour pouvoir les utiliser.

public class Chat{
    //variables static
    static int numero=0;
    //variables d’instances
    int poids;
    String nom;
    Chat(int poids, String nomN){
        this.poids = poids;
        numero++;
        this.nom=nomN;
    }
    void afficherChat(){
        System.out.println( nom + ««+poids);
    }
    public static void main(String args[]){
        Chat monChat=new Chat( 8, "tigrou");
        monChat.afficherChat();
        System.out.println(Chat.numero);
    }
}

Réaliser une méthode qui permet d’afficher l’adresse MAC et une méthode qui permet d’afficher le code du constructeur.

La visibilité

Les objets qui héritent d’une classe ont accès :

  • aux propriétés et méthodes public.
  • aux propriétés et méthodes protected.

Et n’ont pas accès

  • aux propriétés et méthodes private.
z.getNom() ;
z.getAdresse() ;
z.getReducion() ;

Le mot clef protected limite donc l’accès aux objets qui l’hérite.
On peut noter que le modificateur protected (en plus de private et public) permet de rendre accessible les objets à d’autres classes au sein d’un héritage.

 

Les objets qui n’héritent pas d’une classe ont accès :

  • aux propriétés et méthodes public.

Et n’ont pas accès

  • aux propriétés et méthodes private.
  • aux propriétés et méthodes protected.

Le respect de l’encapsulation grâce au accesseurs et modificateurs implique que les propriétés sont déclarées à private. On ne peut donc plus acceder directement à celle-ci en dehors de la classe même avec l’héritage.

Le polymorphisme

La surcharge

La surcharge permet de déclarer des fonctions possédants le même nom mais avec des paramètres différents dans la même classe.

// dans Client
public double somme(double valeur){
        return this.getReduction()+valeur;
        }

public double somme(double valeur1,double valeur2){
        return this.getReduction()+valeur1+valeur2;
        }

// Autre exemple
public class Chat {
    //variables static
    static int numero = 0;

    //variables d’instances
    int poids;
    String nom;

    Chat(int poids, String nomN) {
        this.poids = poids;
        numero++;
        this.nom = nomN;
    }

    void afficherChat() {
        System.out.println(nom + " " + poids);
    }

    void afficherChat(String annee) {
        System.out.println(annee + nom + " " + poids);
    }

    public static void main(String args[]) {
        Chat monChat = new Chat(Tigrou, 8);
        monChat.afficherChat();
        System.out.println(Chat.numero);
        monChat.afficherChat("23/12/1980");
    }
}

La redéfinition (spécialisation ou overriding)

La redéfinition est le fait de déclarer une méthode avec le même nom et les mêmes paramètres mais dans une classe qui l’hérite.

// dans Client
public String toString(){
        return this.getNom()+" "+this.getCode();
}

//---------------------------------------------------------------
// dans ClientParticulier
public String toString(){
        return super.toString()+this.getReduction();
}

Le mot clef final

Une classe final est une classe qui ne peut pas avoir de filles. Une classe final ne peut pas être étendue: le mécanisme d’héritage est bloqué. Mais une classe final peut évidemment être la fille d’une autre classe.

public final class ClientParticuler{}

Une méthode final est une méthode qui ne peut pas être redéfinie dans les sous-classes. Le mot clef final pour un paramètre bloque la modification de sa valeur (constante).

public final somme(){}

Le mot clef abstract

Une méthode abstraite ne contient pas de définition, uniquement sa signature. Une méthode abstraite ne peut pas être déclarée static ou private ou final.
Dès qu’une classe contient une méthode abstraite, elle doit elle aussi être déclarée abstraite, avec le modificateur abstract placé au début de son en-tête.

public class Cient{
public abstract double somme( double valeur) ;
}

Une classe abstraite ne peut être instanciée. Si une classe l’étend, il faudra définir toutes les méthodes abstraites qu’elle contient pour pouvoir l’utiliser.
Une sous-classe d’une classe abstraite sera encore abstraite si elle ne définit pas toutes les méthodes abstraites dont elle hérite.

public abstract class client{}
  public static void main(String args[]{
  C

lient c=new Client() ;

}

Le transtypage

Le transtypage (conversion de type ou cast en anglais) consiste à modifier le type d’une variable ou d’une expression.

double d; int i;
d=3.4 ;
i = (int) d; //transtypage d'un double en int

Il est possible de convertir un objet d’une classe en un objet d’une autre classe si les classes ont un lien d’héritage

On imagine une classe Capitale qui hérite de Ville.

Ville v;
Capitale c = new Capitale("Paris", "France");
v = c; //transtypage implicite d'une Capitale en Ville

Toutefois, une ville n’est pas une capitale par défaut. Si on souhaite la transformer en capitale, il faut faire un transtypage ou un cast explicite.

Ville v = new Ville() ;
Capitale h = (Capitale)v; //transtypage d’une Ville en Capital

Les interfaces

Une interface ne contient que des méthodes abstraites et des constantes. Il n’est pas utile de déclarer les méthodes avec le mot clef abstract. Toutes les méthodes sont abstraites et public.
Toutes les variables sont static et final, ce sont des constantes.

public interface Exemple1 {
int minimum() ;
}

Si une interface hérite d’une autre interface, il faut utiliser le mot clef extends. L’interface ne peut hériter de plusieurs interfaces

public interface Exemple {
int minimum() ;
}
public interface Exemple2 extends Exemple1{
int maximum() ;
}

Une classe implémente une ou plusieurs interfaces

public class maClass implements Exemple2 {
public int minimum(){
return 0 ;
}

public int maximum(){
return 10 ;
}
}

Si une classe hérite d’une interface, il faut le mentionner avec le mot clef implements.

Réaliser une interface comportement qui possède une méthode manger prenant en paramètre de la nourriture et une quantité, une méthode boire prenant en paramètre une quantité, une méthode dormir prenant en paramètre un nombre d’heures.
Réaliser une deuxième interface techniqueChasse qui possède une méthode chasseGroupe et chasseSolitaire ainsi qu’une variable int du nombre moyen de congénère qui sont ensemble lors de la chasse.  Faire en sorte que la classe Sanglier implémente l’interface comportement et l’interface techniqueChasse.

La sérialisation

La sérialisation permet de conserver les objets en les transformant en chaine de caractères. Ils peuvent ainsi être enregistrés dans des fichiers. La sérialisation assure la sauvegarde des valeurs des données de chaque objet lorsque ces données sont de types élémentaires (int, double…) ainsi que la conservation des liens avec d’autres objets.

public class serial_schtroumf {
    public static void main(String args[]) {
        Schtroumf str = new Schtroumf("programmeur");

        try {
            FileOutputStream f = new FileOutputStream("schtroumft.obj");
            ObjectOutputStream s = new objectOutputStream(f);
            s.writeObject(str);
            s.flush();
        }catch(IOException e) {
            System.out.println("probleme IO");
        }
    }
}
public class serial_schtroumf2 {
    Public

    static void main(String args[]) {
        Schtroumf str = new Schtroumf(" &  programmeur & ");

        try {
            FileInputStream f = new FileInputStream(" &  schtroumft.obj & ");
            ObjectInputStream s = new objectInputStream(f);
            str = (Schtroumf) s.readObject();
        } catch (IOException e) {
            System.out.println(" &  nouveau fichier");
        }
        Catch(ClassNotFoundException e) {
            System.out.println(" &  probleme & ");
        }
        System.out.println(str);
    }
}

Accès aux bases de données

Pour accéder aux bases de données depuis du code Java, il y a plusieurs possibilités. Il est possible de télécharger le pilote JBDC du SGBDR. Par exemple, on peut installer le driver JDBC de MySQL. Il permet de se connecter via Java à un SGBDR.

public static void main(String[]args){
    try{
        Class.forName("com.mysql.jdbc.Driver");
        System.out.append("driver ok");
        Connection conn=DriverManager.getConnection("jdbc:mysql://localhost/maBase","login","mdp");
        System.out.append("connection ok");
    }catch(Exception e){
        e.printStackTrace();
    }
}

Création de la requête, on affiche les valeurs de chaque colonne en supposant que la méthode toString de chaque objet est définit.

Statement state=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
        ResultSet.CONCUR_UPDATABLE);
        ResultSet result=state.executeQuery("SELECT * FROM professeur");
        ResultSetMetaData resultMeta=result.getMetaData();

//On créer une requête SQL que l’on exécute un peu comme en PHP.
//Affichage de données
        System.out.println(result.getString("prof_nom")+" "+result.getString("prof_prenom"));

//On affiche le nom et le prenom
        for(int i=1;i<=resultMeta.getColumnCount();i++)
        System.out.print(resultMeta.getColumnName(i));

//On affiche les colonnes
        while(result.next()){
        for(int i=1;i<=resultMeta.getColumnCount();i++){
        System.out.print(result.getObject(i).toString());
        }
        }

Modification de données

On modifie les options du statement pour le rendre modifiable

Statement state = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
String query = "SELECT prof_id, prof_nom, prof_prenom FROM
professeur " + "WHERE prof_nom = 'MAMOU'";
ResultSet res = state.executeQuery(query);
res.first();

On exécute une requête et on se positionne à la première ligne.

res.updateString("prof_nom", "LEMEUR");
res.updateString("prof_prenom", "Fréderic");
On modifie les valeurs du resultSet
res.updateRow();

On ferme le resultSet et le statement pour ne pas surcharger la mémoire du SGBDR après avoir effectué ses requêtes.

result.close();
state.close();

Les requêtes préparées ( à utiliser)

Comme en PHP, il est possible de préparer les requêtes.

Après avoir initialiser

conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);

On modifie les options du statement.

String query = "SELECT prof_nom, prof_prenom, prof_id FROM professeur";
query += " WHERE prof_nom = ?";
query += " OR prof_id = ?";

On utilise le ? pour définir une variable.

PreparedStatement prepare=conn.prepareStatement(query);
        prepare.setString(1,"John");
        prepare.setInt(2,2);
        ResultSet r=prepare.executeQuery();
        String nom;int num;
        while(r.next()){
            nom=rs.getString("prof_nom");
            num=rs.getInt("prof_id");
            SOP(nom+" "+num);
        }

Chaque get correspond à un champ de la requête SQL. Par exemple getString(« prof_nom »)  renvoie le nom du professeur. Il est possible de remodifier les variables à tout moment

prepare.setString(1, "TOTO");

 

La composition ou l’agrégation

Lorsqu’un objet ne peut exister que s’il est constitué de plusieurs objets, on dit que le premier est composé des autres objets élémentaires. La relation qui en découle est une composition. Cette relation affecte le constructeur.
Si on représente une personne qui est constitué d’un état civil, la classe Personne devra être construit avec un objet de la classe Etat_Civil. Si un objet est composé de plusieurs objets, nous gérons cette composition en utilisant une collection d’objet et non plus un simple objet dans la classe.

import java.io.*;

class Personne {
    private String nom;
    private int annee_naissance;
    private Etat_Civil a_pour_etat_civil;

    public Personne() {
        nom = Saisie.lire_String(«adresse ?»);
        adresse = Saisie.lire_String(«adresse ?»);
        etat_civil = new Etat_Civil();
    }

    public String toString() {
        return (nom +» «+annee_naissance +» «+salaire + this.etat_civil);
    }
}

class Etat_Civil {
    private String date_naissance;
    private String lieu_naissance;
    private String nationalite;

    public Etat_Civil() {
        date_naissance = Saisie.lire_String(«date de naissance ?»);
        lieu_naissance = Saisie.lire_String(«lieu de naissance ?»);
        nationnalite = Saisie.lire_String(«nationalite ?»);
    }

    public void affiche() {
        System.out.println(date_naissance);
        System.out.println(lieu_naissance);
        System.out.println(nationalite);
    }
}

Réaliser la classe logement. Elle est composée de pièces, possède une surface, une adresse, un prix.
Une pièce possède une largeur, une longueur et une hauteur. La pièce possède un libellé (chambre, cuisine etc).
Créer deux objets correspondant à la classe.

Les collections

Le Framework de Java définit 6 interfaces en relation directe avec les collections qui sont regroupées dans deux arborescences :

Le JDK ne fournit pas de classes qui implémentent directement l’interface Collection. Le tableau ci-dessous présente les différentes classes qui implémentent les interfaces de bases Set, List et Map :

Set
collection d’éléments uniques
List
collection avec doublons
Map
collection sous la forme clé/valeur
Tableau redimensionnable ArrayList
Arbre TreeSet TreeMap
Liste chaînée LinkedList
Collection utilisant une table de hachage HashSet HashMap

Les listes

Les ArrayList correspondent à des collections sans contraintes. La taille est dynamique, on peut mettre des doublons.

ArrayList monArrayList<Voiture> = new ArrayList() ;
monArrayList.add(new Voiture(«XX-960-XX » ));
monArrayList.add(new Voiture(«XX-970-XX » ));
monArrayList.add(new Voiture(«XX-980-XX » ));
for(Voiture v : monArrayList)
{
  System.out.println( v.getImmatriculation());
}

Les Listes Chaînées avec LinkedList

Une liste chaînée est une liste dont chaque élément est relié au suivant par une référence à ce dernier.
Une liste chaînée peut être utilisée dans le cadre d’une simulation de pile ou de file, FIFO(First In First Out) ou FILO(First In Last Out).
Pour bien comprendre le principe des listes chaînées, rien de mieux qu’un petit schéma :
liste
Chaque élément contient une référence sur son suivant. On remarque que la queue n’a pas de suivant. Son suivant est en fait null.

Une liste chaînée est une liste dont chaque élément est relié au suivant par une référence à ce dernier, sa taille n’est pas fixe. Les LinkedList acceptent tout type d’objet.
Chaque élément contient une référence sur l’élément suivant sauf pour le dernier : son suivant est en fait null.

LinkedList<String> listeChainee = new LinkedList<String> ();
listeChainee.add("element 1");
listeChainee.add("element 2");
listeChainee.add("element 3");
for (String a : listeChainee) {
  System.out.println(a);
}

Les listes chainées ne sont pas adaptés aux données volumineuses.

Les collections sans doublons avec HashSet

Un Set est une collection sans ordre de tri qui n’accepte pas les doublons. Elle n’accepte qu’une seule fois la valeur null, car deux fois cette valeur est considérée comme un doublon.

Set<String> monHashSet>=new HashSet<String> ();
monHashSet.add(« coucou »);
monHashSet.add(« coucou 1 »);
monHashSet.add(« coucou 2 »);
for (String s : monHashSet) {
  System.out.println(s);
}

Les dictionnaires avec HashMap

Ce type d’objet rentre dans la catégorie des dictionnaires Map ou. Les données vont être enregistrées grâce à des clés. On accèdera à ces valeurs en renseignant la clef ou énumérant toute la collection.

HashMap<Integer, String> monHashMap = new HashMap <Integer, String> ();
monHashMap.put(new Integer(12), "printemps");
monHashMap.put(new Integer(16), "été");
monHashMap.put(new Integer(17), "automne");
monHashMap.put(new Integer(15), "hiver"); 

//parcours sur les objets
for (Map.Entry<Integer, String> e : ht.entrySet()){
  System.out.println(e.getKey() + " : " + e.getValue());
}
//parcours sur les clefs
for (String mapKey : monHashMap.keySet()) {
  System.out.println(monHashMap.get(mapKey)) ;
}

Réaliser une collection ArrayList avec 15 entiers (positifs et négatifs)
Afficher les éléments de rang pair
Réaliser une collection HashMap qui permette d’enregistrer 4 voitures. La clef sera l’immatriculation.
Afficher les éléments de la collection grâce à leurs clefs.

Les exceptions

Le code peut générer des erreurs à l’exécution. Le programme va alors s’arrêter. Pour éviter que le programme s’arrête, il est possible de capturer ces erreurs.

hierarchie d'exceptions

La classe Error représente une erreur grave intervenue dans la machine virtuelle Java ou dans un sous-système Java. L’application Java s’arrête instantanément dès l’apparition d’une exception de la classe Error.
La classe Exception représente des erreurs moins graves. Les exceptions héritant de la classe RuntimeException n’ont pas besoin d’être détectées impérativement par des blocs try/catch.

Rattraper une exception

public static void main(String[]args){
        int x,y;
        double z;
        Scanner sc=new Scanner(System.in);
        x=sc.nextInt(«entrez une valeur»);
        y=sc.nextInt(«entrez une valeur»);
        try{
        z=x/y;
        }catch(Exception e){
        System.out.println(«erreur»);
        }finally{
        System.out.println("le pogramme continue");
        }
}

On capture l’erreur grâce au catch. Ici on capture les exceptions de type Exception.
On notera que l’instruction catch permet de prendre différents types d’exceptions que nous verrons ultérieurement.
La clause finally définit un bloc qui sera toujours exécuté,

Rattraper plusieurs exceptions

try{
        z=x/y;
        }catch(RuntimeException e){
        System.out.println(«erreur Runtime»);
        }catch(Exception e){
        System.out.println(«erreur Exception»);
        }finally{
        System.out.println("le pogramme continue");
        }

Il est également possible d’imbriquer les constructions try catch.

Créer un type d’exception

class NombreHabitantException extends Exception{
//le constructeur
public NombreHabitantException(){
  System.out.println("Vous essayez d'instancier une classe Ville avec un nombre d'habitants négatif !");
}
}

On ne peut créer d’exception héritant de la classe Error.

Lancer une exception

System.out.println("Coucou 1");
if (true) throw new Stop();
System.out.println ("Coucou 2");
System.out.println ("Coucou 3");
System.out.println ("Coucou 4");
class Stop extends RuntimeException {}

On lance une exception en utilisant le mot clef throw.

Affichage:

Coucou 1
Exception in thread "main" Stop
at Arret.main(Arret.java:5)

La déclaration des exceptions dans les méthodes

class Factorielle {
    static int factorielle(int n) throws PasDefini {
        int res = 1;
        if (n<0){
            throw new PasDefini();
        }
        for(int i = 1; i <= n; i++) {
            res = res * i;
        }
        return res;
    }

    public static void main (String [] args) {
        int x;
        System.out.println("Entrez un nombre (petit):");
        x = sc.nextInt();
        try {
            factorielle(x);
        } catch (PasDefini e) {
            System.out.println("La factorielle de "+x+" n’est pas définie !");
        }
    }
}
class PasDefini extends Exception {}

On déclare une fonction qui déclenche une exception en utilisant le mot clef throws.

Réaliser une classe EntierNaturel permettant de manipuler des entiers naturels (positifs ou nuls)
La classe possèdera un constructeur avec un seul argument de type int qui générera une exception de type ErrVal lorsque la valeur reçu n’est pas comprise entre 10 et 100 (grâce à throws). La classe possèdera un accesseur sur la valeur fournie
Ecrire ensuite un programme qui traite l’exception ErrVal en affichant un message.

La généricité

La généricité permet de définir des classes avec un (ou plusieurs) type d’objet inconnu, ou générique qui va être déterminé à l’exécution. Les collections utilisent des types génériques.

ArrayList<Client> maCollection = new ArrayList();

Soit la classe suivante :

public class Value {
    private int v;
    public setValue (int v){
        this.v = v;
    }
    public int getValue(){
        return this.v;
    }
}

Si jamais nous avons besoin de la même classe mais avec une variable de type double ou Client, nous sommes tenté de refaire une autre classe. En utilisant la généricité, nous n’allons faire qu’une seule classe. Ici on déclare une classe avec un type d’objet que l’on nomme T. La classe peut fonctionner avec n’importe quel type !

public class Value<T> {
    private T v;
    public setValue (T v){
        this.v = v;
    }
    public T getValue(){
        return this.v;
    }
}
Value monObjet<Client> v1 = new Value ();

On peut aussi hériter la classe générique

public class UtilisateurValue extends Value<Utilisateur> {}

Plusieurs types génériques dans une classe

On peut utiliser autant de type générique que l’on souhaite. Ici on déclare une classe avec un deux objets génériques que l’on nomme A et B.

public class Value<A,B> {
    private A a;
    private B b;
    public Value(A a, B b){
        this.a=a;
        this.b=b;
    }
    public setValue (A a){
        this.a = a;
    }
    public A getValue(){
        return this.a;
    }
//…
}
Value<String, Boolean> maValue = new Value ("test", true);

Le Mapping Objet

Un mapping objet et base relationnel permet de créer l’illusion d’une correspondance entre la base de données et les objets du langage de programmation. On fait donc correspondre les attributs des objets avec les attributs de la base de données. On parle d’ORM (object-relational mapping).

Le pattern DAO consiste à ajouter un ensemble d’objets dont le rôle sera d’aller lire, écrire, modifier, supprimer. Cet ensemble d’objet s’appelle la couche DAO. Ce pattern utilise des classes génériques. On part de nos classes et on réalise des classes qui vont faire la liaison avec la base de données. Ces classes vont porter le nom du pattern : XxxDAO. Ces classes héritent d’une classe DAO qui définit la généricité.

Classe Langage

Notre classe de départ que l’on veut mapper dans la base

public class Langage {
    private long id;
    private String nom;

    public Langage(long id, String nom){
        this.id=id;
        this.nom=nom;
    }

    public Langage(){
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }
}

La classe générique DAO

import java.sql.Connection;
public abstract class DAO<T> {
    public Connection connect = null ;
    public abstract T select(long id);
    public abstract T insert(T obj);
    public abstract T update(T obj);
    public abstract void delete(T obj);
}

On définit la signature de plusieurs méthodes abstraites qui permettent de manipuler des données.

La classe LangageDAO

Elle hérite de la classe DAO pour MYSQL

import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LangageDAO extends DAO<Langage> {
    Connection connection = null;
    public Connection getConnection() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            if (connection == null) {
                try {
                    connection = DriverManager.getConnection("jdbc:mysql://localhost/societe?user=root&password=");
                } catch (SQLException ex) {
                    Logger.getLogger(LangageDAO.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return connection;
    }

    La fonction getConnection renvoie la connexion.
    On implémente ici les méthodes abstraites de la classe générique
    public Langage insert(Langage obj) {
        try {
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery("SELECT max(lan_id)+1 as lan_id FROM langage ");
            resultSet.next();
            int id = resultSet.getInt("lan_id");
            resultSet.close();
            statement.close();


            On recherche le dernier id des objets langage dans la base.
                    PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO langage (lan_id, lan_nom) VALUES ( ? , ?)");
            preparedStatement.setString(1, ((new Long(obj.getId())).toString()));
            preparedStatement.setString(2, obj.getNom());
            preparedStatement.executeUpdate();
            preparedStatement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return obj;
    }

    public Langage select(long id) {
        Langage lang = new Langage();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(
                    "SELECT * FROM langage where lan_id = ? ");
            preparedStatement.setString(1, (new Long(id).toString()));
            ResultSet result = preparedStatement.executeQuery();
            lang = new Langage(id, result.getString("lan_nom"));
            preparedStatement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return lang;
    }
    public Langage update(Langage obj) {
        try {
            PreparedStatement preparedStatement = connection.prepareStatement("UPDATE langage SET lan_nom = '" + obj.getNom() + "'"
                    + " WHERE lan_id = " + obj.getId());
            ResultSet result = preparedStatement.executeQuery();
            obj = this.select(obj.getId());
            preparedStatement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return obj;
    }
    public void delete(Langage obj) {
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(
                    "DELETE FROM langage WHERE lan_id = " + obj.getId());
            ResultSet result = preparedStatement.executeQuery();
            preparedStatement.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Liaison automatique

La plupart des logiciels de développement génère la couche DAO automatiquement. En pratique, on ne gère pas la base de données. On définit la plupart du temps des annotations spécifiques pour que le service qui effectue la liaison réalise la correspondance entre table et objet. L’ORM Doctrine permet de gérer automatiquement la liaison avec la base de données. On ne s’occupe plus du pattern DAO. Nous le verrons grâce à Symfony qui utilise cet ORM.

Les Tests

Les tests permettent de vérifier que le programme effectue bien les services demandés. Ces tests vont informer les développeurs des erreurs éventuelles du code testé.

Un service correspond à ce qu’on attend de la fonction. Une fonction peut rendre plusieurs services, comme ajouter une valeur à un nombre ET vérifier qu’il est positif.

Pour tester, il faut réaliser quatre étapes :

  1. on définit les services de chaque fonction
  2. on définit par la suite les tests de chaque service
  3. on implémente les fonctions
  4. on teste les fonctions

On définit les tests selon des services avant l’implémentation de la fonction. Sénèque le jeune : ’Errare humanum est’. L’erreur est humaine. Il est donc important de tester pour être certain que nous avons bien réalisé notre code. Les tests informent de la qualité du code.

Le contrôle de résultat

Voici une classe adition que l’on souhait tester.

public class Addition {
    public Long calculer(Long a, Long b) {
        return a+b;
    }
    public Character lireSymbole() {
// Erreur d’implémentation
        return ’-’;
    }
}

La première approche est de tester le code en renvoyant le résultat.

public static void main(String[] args) {
        Addition operation = new Addition();
        Long resultat = operation.calculer(new Long(6), new
        Long(3));
        System.out.println("L’addition de 6 et 3 retourne " + resultat.toString());
}

 

On pourra comparer directement si l’on obtient ce que l’on souhaite
L’addition de 6 et 3 retourne 9
On s’assure que le résultat obtenu est bien celui attendu. Mais il faut un contrôle humain pour s’assurer du bon résultat.
Dans un deuxième temps, on peut demander à l’utilisateur de renvoyer un résultat binaire : OK.

En améliorant le test on obtient :

public static void main(String[] args) {
        Addition operation = new Addition();
        Long resultat = operation.calculer(new Long(6),
        new Long(3));
        if (resultat.equals(new Long(9)))
        System.out.println("Test OK");
        else
        System.out.println("Test KO");
}

La console affiche maintenant :

Test OK

Rapport de tests

Ajoutons maintenant un nouveau test sur la méthode lireSymbole :

public static void main(String[] args){
        Addition operation=new Addition();
        Long resultat=operation.calculer(new Long(6),newLong(3));
        if(resultat.equals(new Long(9)))
        System.out.println("Test OK");
        else
        System.out.println("Test KO");
        Character c=operation.lireSymbole();
        if(c.equals(’+’))
        System.out.println("Test OK");
        else
        System.out.println("Test KO");
}

La console affiche maintenant deux résultats :

Test OK
Test KO

Le second test échoue. Il va falloir déterminer où est l’erreur. Avec plusieurs tests d’affiler, il devient très difficile de repérer la fonction correspondante.

Création de tests unitaires

En Java, nous allons utiliser JUnit pour réaliser des tests. JUnit est intégré dans l’environnement de développement avec l’ajout de plug in. Il permet d’avoir un rapport de test en plus du rapport de compilation. Il donne un résultat binaire de l’exécution des tests avec un descriptif de l’erreur.

Il affiche une interface en couleur qui permet d’observer rapidement si nos fonctions ont passé les tests.

Structuration des tests avec JUnit

Les tests portant sur une classe X seront regroupés dans une classe nommée XTest.

import org.junit.Test;
import org.junit.Before;
import org.junit.After;
import org.hamcrest.*;
public class AdditionTest {
protected Addition op;

@Before
public void setUp() {
op = new Addition();
}

@After
public void tearDown() {
}

@Test
public void testCalculer() throws Exception {
// Tester quelque chose
}

@Test
public void testLireSymbole() throws Exception {
// Tester quelque chose
}
}

On utilise les annotations commençant par @ pour définir les tests. L’annotation @before définit que la fonction sera lancée avant les tests. Ce qui est utile pour initialiser des variables par exemple.

Les assertion avec JUnit

Dans la classe de test, nous allons définir des assertions. Les assertions sont des éléments de validation qui permettent de tester le programme automatiquement avec JUnit.

@Test
public void testCalculer() throws Exception {
Assert.assertEquals(op.calculer(new Long(1),new Long(3)), new Long(4));
}

@Test
public void testLireSymbole() throws Exception {
Assert.assertEquals(op.lireSymbole(), is(’+’));
}

Réaliser une classe TVA qui possède une variable TVA, implémente les accesseurs et modificateurs. Cette classe définit une méthode qui permet de calculer le prix ttc en fonction du prix HT.
Ecrire ensuite la classe Test correspondante avec des assertions.

Réaliser une classe Salarier. Un salarié possède un nom, un prénom, un salaire brut mensuel.
Réaliser une méthode qui permet de renvoyer le salaire net qui correspond à 83% du salaire brut plus 25 euros de prime.
Réaliser une méthode qui renvoie le salaire annuel net.
Ecrire ensuite la classe Test correspondante.
On affichera un message « debut Test » au commencement des tests

On trouvera les différentes fonctions sur ce site :
http://junit.sourceforge.net/javadoc/org/junit/Assert.html

assertTrue(java.lang.String message, boolean condition)
Asserts that a condition is true.
assertFalse(java.lang.String message, boolean condition)
Asserts that a condition is false.
assertEquals(java.lang.String message, java.lang.Object expected, java.lang.Object actual)
Asserts that two objects are equal.

Les différents tests

Les tests unitaires
Un test est dit unitaire lorsqu’il teste les méthodes d’une classe de façon atomique et indépendante. Ces tests ne font intervenir en général que la classe et la méthode ciblée par le test.

Les tests d’intégration
Les tests d’intégration permettent de valider que l’application fonctionne correctement après la mise en commun des différentes parties. On peut y voir une double position.

Les tests fonctionnels
Les tests fonctionnels viennent valider le fonctionnement de l’application et du service rendu au client. Ces tests portent en général sur des classes de haut niveau d’abstraction. Ils permettent typiquement de valider un enchaînement d’actions au travers d’un scénario client.

Les tests de performance
La phase de validation permet également de vérifier que les contraintes de performance sont atteintes. Ces tests valident typiquement le passage à l’échelle d’un système et valident la qualité de service maximale.

Les tests de recette
Les tests de recette sont sous la responsabilité du client et sont réalisés par un panel d’utilisateurs représentatifs. Ils mettent en œuvre l’application livrée dans des conditions réelles et vérifient son bon comportement.