Master 2 CCI 2012-2013
POO, langage Java
Henri Garreta 

1. Exercices simples pour commencer

        1. L’incontournable « Print "Hello" »
        2. Random
        3. A propos de tableaux
        4. Lectures simples au clavier : la classe Scanner
        5. Quel jour sommes-nous ?
        6. Jeux avec les chaînes
        7. Calcul de la factorielle
        8. Les arguments de la ligne de commande
Le signe © renvoie à la correction

1.1. L’incontournable « Print "Hello" » ©

Saisissez, compilez et exécutez un programme Java qui affiche Bonjour à tous ! sur l’écran de la console. Pour cela, écrivez une classe publique exécutable nommée Bonjour placée dans un fichier nommé Bonjour.java. Trois « détails » à ne pas oublier :

  1. Une classe est exécutable si et seulement si elle comporte une méthode ayant exactement la signature « public static void main(String[] args) »
  2. On provoque une compilation en donnant un nom de fichier (ex.: javac Bonjour.java)
  3. On lance l’exécution d’un programme en donnant un nom de classe (ex.: java Bonjour).

Observez ce qui se passe lorsque vous désobéissez à une des trois prescriptions précédentes.

1.2. Random ©

Afin de constater l’existence dans la bibliothèque Java d’un générateur de nombres pseudo-aléatoires, écrivez un programme qui obtient n nombres « au hasard » (par exemple, n = 100 000) et qui calcule la moyenne et l’écart-type de la suite ainsi déterminée.

Pour produire des nombres pseudo-aléatoires utilisez la méthode java.lang.Math.random() (cela se lit : « la méthode random() de la classe Math du paquetage java.lang »), sur laquelle vous trouverez des indications dans la documentation de l’API. Essentellement, il faut savoir que chaque fois qu’on l’appelle, cette méthode renvoie un nombre flottant de l’intervalle [0 ; 1[ (0 est compris, 1 exclu).

Un des buts de cet exercice est justement de vous initier à la consultation de la documentation Java. Pour cela, ouvrez un navigateur sur la « doc de l’API » (soit chez Sun, http://java.sun.com/javase/6/docs/api/, soit plus près de nous www.dil.univ-mrs.fr/~garreta/docJava/api/) ; dans le volet supérieur gauche sélectionnez le paquetage java.lang et, alors, dans le volet inférieur gauche sélectionnez la classe Math. Parmi les méthodes de cette classe, cherchez random et lisez-en la documentation.

Notes. Vous pouvez aussi employer des méthodes de la classe java.util.Random, qui est entièrement consacrée à la génération de suites pseudo-aléatoires ; cependant, pour ce que nous avons à faire ici, la méthode java.lang.Math.random() suffit amplement. Bien entendu, si vous utilisez la classe java.util.Random, évitez de nommer Random votre propre classe !

Rappel des formules. Si n est le nombre de termes d’une suite, S = x1 + x2 + ... + xn la somme de ces termes et Q = x12 + x22 + ... + xn2 la somme de leurs carrés, alors

N.B. Les statisticiens nous apprennent que, si la distribution des valeurs renvoyées par la fonction random est uniforme, quand n devient de plus en plus grand m tend vers 0,5 et s vers 0,288675134595 (la racine carrée de 1/12).

1.3. A propos de tableaux ©

Écrivez une méthode statique qui reçoit deux tableaux triés de nombres entiers et qui construit et renvoie un troisième tableau, également trié, constitué par la fusion des deux tableaux donnés. Les doublons seront éliminés ; cependant, le tableau résultat sera « plein » (c’est-à-dire ayant exactement le nombre d’éléments nécessaire).

Pour essayer cette méthode, écrivez un programme (méthode main) qui initialise deux tableaux avec des constantes, les affiche et affiche également le résultat de leur fusion.

1.4. Lectures simples au clavier : la classe Scanner ©

Le but de cet exercice est de vous initier à l’utilisation de la classe java.util.Scanner, qui permet d’effectuer simplement des lectures à la console, comme on le fait en C avec la fonction scanf. Cette classe est disponible à partir de la version 5 de Java.

Cela s’emploie de la manière suivante : au début du programme, on crée une instance (nommée ici entree) connectée à un flot en entrée, qui très souvent est l’entrée standard System.in :

Scanner entree = new Scanner(System.in);

ensuite, pour lire un entier i il suffit d’écrire

i = entree.nextInt();

pour lire un flottant x :

x = entree.nextFloat();

Pour lire une chaîne s

s = entree.nextLine();

La chaîne renvoyée comme résultat par nextLine sera formée de tous les caractères qu’on va trouver sur System.in à partir de maintenant et jusqu’au prochain caractère de fin-de-ligne (on produit un caractère fin-de-ligne au clavier en pressant la touche « Entrée »). Le caractère fin-de-ligne lui-même sera lu, mais n’apparaîtra pas dans la chaîne résultat.

Exercice. Pour essayer la classe Scanner, écrivez en Java le programme qui calcule et affiche la moyenne d’une suite de nombres décimaux positifs ou nuls, lus au clavier, dont la fin est indiquée par un nombre négatif. Exemple d’exécution (ce qui a été tapé par l’utilisateur est souligné) :

Donner les nombres (terminer par -1): 14  8,5 
10 
12  5,5  -1 
moyenne: 10,0

N.B. 1 - La classe Scanner prend en compte les particularités locales, c’est pourquoi il faut écrire les nombres décimaux avec une virgule à la place du point, comme ci-dessus. C’est également le cas de la méthode printf (employée ci-dessus pour obtenir l’affichage de la moyenne), mais non des méthodes plus rustiques print et println.

N.B. 2 - Dans la lecture d’un nombre, les éventuels caractères blancs (espaces, tabulations et fins-de-ligne) précédant le nombre sont toujours « avalés » et n’ont aucun effet. Cependant, les blancs suivant le nombre ne sont pas consommés ; il en est ainsi notamment de la fin-de-ligne souvent tapée pour finir le nombre, qui reste donc disponible pour les prochaines lectures. Cela se passe comme ça dans beaucoup de langages et c’est la cause d’un certain nombre de dysfonctionnements lorsqu’une lecture de nombre est suivie d’une lecture de chaîne (à méditer).

1.5. Quel jour sommes-nous ? Quelle heure est-il ? ©

Le but de cet exercice est de vous faire essayer diverses manières d’obtenir et afficher la date courante et, surtout, un prétexte pour vous faire compulser la documentation...

A. Première manière : la méthode java.lang.System.currentTimeMillis() donne la date courante, exprimée comme le nombre de millisecondes qui se sont écoulées depuis le 1er janvier 1970 à 0 heures GMT. C’est précis, mais pas très pratique pour organiser sa semaine ! (Retenez quand même l’existence de cette méthode, car elle est bien utile pour mesurer les performances des programmes).

Écrivez un programme qui affiche le nombre s de secondes écoulées depuis le 1er janvier 1970. Exécutez deux fois ce programme, à une minute d’intervalle, et voyez si l'écart des valeurs obtenues illustre l’explication donnée. Constatez que le nombre d'années exprimées par la valeur s est vraisemblable.

B. Deuxième manière : ajoutez au programme précédent des instructions qui créent un objet de type java.util.Date (par une expression comme « Date d = new Date(); ») et le donnent à afficher à System.out. Comme vous le voyez, c’est mieux, car on obtient bien une date, mais écrite à la manière des anglo-saxons.

Ne cherchez pas la correction de ce défaut parmi les nombreuses méthodes de la classe Date, elles sont presque toutes deprecated (désapprouvées, c'est-à-dire en voie de péremption) et ne méritent pas qu’on s’y investisse.

C. Troisième manière : créer un objet de type java.util.Calendar (par une expression comme « Calendar c = Calendar.getInstance(); ») et obtenir séparément les éléments de la date (le jour de la semaine, le jour du mois, le mois, l’année) pour les afficher comme bon nous semble.

En étudiant la documentation de la classe Calendar vous apprendrez qu’on obtient les divers composants par des expressions de la forme « c.get(Calendar.MONTH); »,  « c.get(Calendar.YEAR); », etc.

Des tableaux de chaînes déclarés comme ceci peuvent vous aider à produire une présentation soignée :

String[] mois = { "janvier", "février", ... "décembre" };
String[] jSem = { "lundi", "mardi", ... "dimanche" };

D. Quatrième manière (la plus « pro ») : construire un objet d de type java.util.Date comme dans la deuxième manière et un objet f de type java.text.SimpleDateFormat (qui est une variété de java.text.DateFormat) et afficher le résultat du formatage du premier par le second, par une expression comme f.format(d).

Ne vous laissez pas effrayer par la volumineuse documentation de SimpleDateFormat. Si vous ne voyez pas comment cela marche, essayez ceci et vous comprendrez :

...
Date d = new Date(); 
SimpleDateFormat f = new SimpleDateFormat("dd MMMMM yyyy HH:mm"); 
System.out.println("maintenant: " + f.format(d));
...

1.6. Jeux avec les chaînes ©

But de cet exercice : vous faire explorer la classe java.lang.String en testant ses diverses méthodes sur des chaînes et d’autres valeurs lues au clavier. Il s’agit d'écrire une classe exécutable TestChaines dont la méthode principale effectue les opérations suivantes :

A. Lire un nombre et le convertir en chaîne (ex.: le nombre 12345 devient la chaîne "12345").

B. Lire une chaîne entièrement faîte de chiffres et la convertir dans le nombre entier qu’elle représente (ex.: la chaîne "12345" devient le nombre 12345). La solution se trouve parmi les méthodes statiques de la classe java.lang.Integer.

Si vous programmez ce test à la suite de celui de la question A vous constaterez que lorsque la lecture d’une chaîne fait suite à celle d’un nombre il est nécessaire de « nettoyer » l’entrée en plaçant entre ces deux opérations la lecture à fonds perdu d’une chaîne, destinée à consommer la marque de fin de ligne (trace de la touche « Entrée ») qui a probablement été tapée à la fin du nombre.

C. Même question que ci-dessus, mais avec un nombre flottant (ex.: la chaîne "0.12345e4" devient le nombre 0.12345e4).

D. Lire une chaîne représentant un nom de ville, lui enlever les éventuels blancs au début et à la fin et l’afficher entièrement en majuscules.

E. Lire deux chaînes s1 et s2 et afficher la réponse à la question : « ces deux chaînes commencent-elles par le même caractère ? » Utilisez la méthode d’instance charAt.

F. Lire deux chaînes s1 et s2 et afficher les résultats renvoyés par les expressions « s1 == s2 », « s1.equals(s2) », « s1.compareTo(s2) » et , « s1.compareToIgnoreCase(s2) ». Entre autres, essayer les couples "abcd" et "abcd", puis "abcd" et "AbcD".

G. Lire deux chaînes s1 et s2 et afficher la réponse aux questions «  s1 commence-t-elle par s2 ? », «  s1 finit-elle par s2 ? » et «  s1 contient-elle s2 ? »

H. Lire deux chaînes s1 et s2 et si s1 contient s2, renvoyer s1 privée de s2 (s’intéresser à substring), sinon renvoyer s1.

I. Si s est une chaîne de caractères, l’expression s.intern() renvoie une chaîne ayant les mêmes caractères que s mais appartenant à une collection de chaînes sans doublons que Java maintient et dont les chaînes figurant dans le programme source font partie d’office.

Lire deux chaînes s1 et s2 et constater qu’à la suite des transformations « s1 = s1.intern(); » et « s2 = s2.intern(); » les expressions « s1.equals(s2) » et « s1 == s2 » deviennent équivalentes.

1.7. Calcul de la factorielle ©

A. Écrivez une classe exécutable avec une méthode :

static long factorielle1(int n)

qui calcule la factorielle de n, c’est-à-dire le nombre n! = n × (n – 1) × (n – 2) × ... × 3 × 2 × 1.

B. Trouvez la valeur de n à partir de laquelle les débordements des valeurs entières rendent cette méthode inutilisable.

N.B. Une manière de vérifier que la valeur de n! est juste, sachant que celle de (n – 1)! l’est, consiste à afficher le rapport n! / (– 1)!

C. Pour pallier ce problème de débordement, écrivez une nouvelle fonction utilisant des objets java.math.BigInteger :

static BigInteger factorielle2(int n)

et constatez que maintenant on peut aller pratiquement aussi loin qu’on veut.

D. Aurions-nous pu donner le même nom aux fonctions factorielle1 et factorielle2 ?

1.8. Les arguments de la ligne de commande ©

Dans sa forme générale, la commande qui déclenche l'exécution d'une application Java s'écrit

java UneClasse chaîne0 chaîne0 ... chaînek–1

chaîne0 chaîne0 ... chaînek–1 sont des chaînes de caractères ne contenant pas de blancs séparées par des blancs (espaces, tabulations).

Ces chaînes sont accessibles depuis l’intérieur de l’application à travers le tableau, généralement appelé args, qui est déclaré dans l’en-tête de la fonction main. Par exemple, si une application est lancée par la commande

java NomDeLaClasse Dupond "Jean Pierre" 2006 2+3=5 
  

alors la fonction main reçoit un argument qui est un tableau formé des quatre chaînes de caractères "Dupond", "Jean Pierre", "2006" et "2+3=5". Notez que :

Exercice. Écrivez une classe Calcul qu’on exécute avec trois arguments : deux nombres et un opérateur entre les deux, et qui affiche le résultat de l’opération indiquée sur les nombres indiqués. Exemple d’exécution (ce qui est saisi par l’utilisateur est bleu) :

java Calcul 1200 + 400
1200 + 400 = 1600