Java/Version imprimable
Une version à jour et éditable de ce livre est disponible sur la Wikiversité,
une bibliothèque de livres pédagogiques, à l'URL :
http://fr.wikiversity.org/wiki/Java
Introduction
Introduction à Java
modifierJava est le langage phare de la société Sun Microsystems. Il a été créé en 1991, à l’époque dans le but d’intégrer des appareils domestiques pour un projet de domotique, dont le nom de code était « Green ». Il fallait donc que le langage soit léger et portable sur toute configuration. Baptisé dans un premier temps « Oak », il changea rapidement de nom, Oak étant déjà utilisé, pour devenir « Java », terme de l’argot en anglais qui signifie café. Les versions suivantes, avec l’ajout notamment de Swing permettant de créer des interfaces graphiques stables, rendront le langage de plus en plus populaire pour la création de nombreux types d’application, avec comme atout principal : sa portabilité. La version actuelle de Java est la version 1.8.
Java se décline en de nombreuses versions, pour ordinateurs (avec une version de la machine virtuelle par système d’exploitation), pour téléphones mobiles, pour la programmation d’applications commerciales… Chacune des versions possède certaines bibliothèques en commun et certaines autres spécifiques, écrites différemment ou absentes. Certains systèmes d’exploitation possèdent la machine virtuelle dans leur configuration de base (Mac OS X…), tandis qu’elle doit être installée séparément sur d’autres (Windows, Mac OS 9…)
Java ressemble en plusieurs points au C++, langage très célèbre et très répandu, considéré souvent comme son grand-frère. Java est donc un langage objet ; toutefois, étant prévu pour tourner sur des petites configurations (souvenons-nous qu’il est prévu à la base pour les appareils ménagers), il est aussi utilisé à la manière d’un langage procédural. Il possède plusieurs autres caractéristiques, dont le fait d’être fortement typé (le type des variables en détermine strictement le type de contenu).
Il est aussi, et c’est là une de ses grandes forces, portable (quasiment) sans modifier une seule ligne de code. En effet, Java est un langage interprété, et cette caractéristique est suffisamment importante pour que nous la développions ici un peu plus. À la différence d’un langage comme son proche parent le C++, il n’est pas compilé pour un type de processeur mais pour une machine virtuelle. C’est cette machine virtuelle (la JVM) qui interprète en temps réel le code précompilé. Ci-dessous, un schéma très simpliste permettant de se représenter la différence entre les deux principes :
On constate clairement ici qu’à la différence d’un langage dit « exécuté », le langage Java nécessite une étape de plus pour être exécuté. La machine virtuelle doit d’abord transformer le « Bytecode » (une sorte semi-code machine) en instructions réelles pour le processeur. Ce dernier doit donc effectuer une opération préalable au lieu de pouvoir immédiatement exécuter le code, d’où une plus grande lenteur d’exécution. C’est à ce prix-là que le langage peut être exécuté sur n’importe quelle machine : c’est en effet la machine virtuelle (qui elle, est programmée pour une architecture bien précise) qui va traduire le code spécialement pour la configuration en question. C’est donc d’une certaine manière la grande force du Java qui fait sa principale faiblesse : sa lenteur d'exécution. Puisque le code doit être traduit en temps réel avant de pouvoir être exécuté, le Java est naturellement plus lourd qu’un autre langage. Son utilisation pour des applications gourmandes telles que les jeux 3D ou les applications de calcul intensif reste donc anecdotique. Il est par contre parfaitement adapté à des applications plus modestes en ressources, et la puissance actuelle des processeurs tend à minimiser cette faiblesse encore flagrante il y a de cela quelques années.
Une autre particularité de Java est de proposer dans son kit de développement, le JDK (Java Developement Kit), un grand nombre (en fonction du type choisi : standard, pour téléphones mobiles…) de bibliothèques prêtes à l’emploi pour tous les domaines utilitaires : gestion des fichiers, classement, recherche, tri… La documentation fournie avec l’API est très complète et très bien organisée ce qui permet de trouver facilement la fonctionnalité dont on a besoin. Ainsi, le programmeur n’a pas à réinventer la roue à chaque nouveau projet, mais peut se concentrer directement sur la partie fonctionnelle de son produit.
Pour commencer à programmer en Java, il suffit de télécharger le JDK, sous Unix :
sudo apt-get install openjdk-6-jdk
Celui-ci contient la machine virtuelle ainsi que les outils nécessaires à la compilation d’un projet. Comme dans beaucoup de langage, il est tout à fait possible de programmer au bloc-notes ou gedit ; toutefois, un environnement de développement digne de ce nom se révélera rapidement nécessaire. Il en existe beaucoup ; JBuilder chez Borland, intégrant un système de modélisation UML performant, XCode chez Apple, bien que peu orienté Java, et bien d’autres encore. Eclipse bénéficie d’une communauté d’utilisateurs très nombreuse. L’important est bien évidemment de trouver un environnement de développement où vous soyez à l’aise et qui vous convienne.
Lancer un programme
modifierFaites ces exercices : Exercices/Commencer à programmer. |
Une fois le JDK installé, créer un fichier bonjour.java contenant le code :
class salut {
public static void main(String[] args) {
System.out.println("Bonjour le monde !");
}
}
Le compiler ensuite en lançant (sous UNIX ou DOS) :
javac bonjour.java
Lancer ensuite le fichier salut.class ainsi généré :
java salut
Liens externes
modifier- [html] • [licence Copyright] • (en) • lien vers le document • Site officiel de Java
- [html] • [licence Copyright] • (en) • lien vers le document • Son tutoriel
- [html] • [licence Copyright] • (en) • lien vers le document • Application : Hello the world !
- [html] • [licence Copyright] • (en) • lien vers le document • La documentation de l'API
- [html] • [licence Copyright] • (en) • lien vers le document • Le site Web d'Eclipse
- [html] • [licence CC-by-sa] • (fr) • lien vers le document • Tomcat : conteneur libre de servlets Java 2 Enterprise Edition.
Variables et types
La base de tout programme est la manipulation de données et d'ailleurs tous les programmes ne sont que ça ! C’est pourquoi il faut savoir quels sont les types de données de base que l’on peut utiliser dans le langage Java mais aussi comment créer des données que l’on appelle variable.
Les types de base
modifierLes types de donnée de base en Java sont :
- boolean : un booléen (d'ordre 2 en réalité) qui ne pourra prendre que les valeurs true ou false.
- byte : un entier relatif très court (entre −128 et 127).
- short : un entier relatif court (entre −32 768 et 32 767).
- int : un entier relatif (entre −2 147 483 648 et 2 147 483 647).
- long : un entier relatif long (entre −9 223 372 036 854 776 000 et 9 223 372 036 854 776 000).
- float : un nombre décimal (entre et ).
- double : un nombre décimal à double précision (entre et ).
- char : un caractère (entre '\u0000' et '\uffff').
- String : une chaine de caractère. NB : ce n'est pas un type primitif mais une classe.
Type primitif | Taille en octets | Valeur par défaut | Représentation | Information complémentaire |
---|---|---|---|---|
boolean | Non spécifié | false | true / false | La taille dépend de la JVM |
char | 2 | '\u0000' | Entre '\u0000' et '\uffff' | Caractère unicode |
byte | 1 | 0 | ||
short | 2 | 0 | ||
int | 4 | 0 | ||
long | 8 | 0L | ||
float | 4 | 0f | Entre et | Précision |
double | 8 | 0d | Entre et | Précision |
Des conversions existent entre ces différents types de données. En effet, il est possible de convertir un float en double, ou encore un int en double. Il est aussi possible de convertir un caractère en entier et inversement. Le meilleur moyen de connaître les conversions possibles est encore de les essayer. Il est cependant inutile d'essayer de convertir un booléen en quoi que ce soit d'autre.
Remarque : dans la pratique, pour représenter des nombres, on utilise le plus souvent que les types int et double. Cela évite en général les problèmes de conversion. Remarque : les chaînes de caractères (String) ne sont pas un type de base en Java, mais sont bel et bien des objets. Le traitement de ce type d'objet en mémoire n’est pas le même que les autres objets.
Déclarer une variable
modifierLa déclaration d'une variable se fait toujours de la même manière quel que soit le type de donnée utilisé (y compris les types qui ne sont pas de base mais cela sera vu dans le chapitre consacré aux objets).
Prenons donc un exemple de déclaration de variable :
public static int monEntier ;
//Je crée ici un entier sans l'initialiser, sa valeur est la valeur par défaut pour le type int: 0.
monEntier = 4 ;
//J’ai maintenant changé la valeur 4 à mon entier.
public static boolean monBooleen = true ;
//Il est aussi possible de donner une valeur à la variable dès sa déclaration.
On peut remarquer ici l'apparition des mots clés public et static, il n’est pas nécessaire de s'en préoccuper, leur signification sera vu dans le chapitre consacré aux objets. Ces termes ne sont d'ailleurs pas obligatoires mais on se contentera de les laisser tant que l’on ne connaît pas exactement leur signification.
Si l’on souhaite donner une valeur particulière à une variable de type char, il faut écrire le caractère entre ' '. Pour les chaînes de caractères, ou String, il faut écrire la chaîne entre " ".
Déclarer une constante
modifierIl arrive parfois que l’on ait besoin d’utiliser des constantes, notamment pour donner un nom explicite à un chiffre, qui sera donc plus simple à manipuler pour notre esprit. La déclaration de constante se fait donc de la manière suivante :
public static final String MA_CONSTANTE = "Peuh" ;
Le mot final indique qu'une fois une valeur donnée, cette variable ne pourra plus en changer.
Remarque : Il est important de garder cette convention de nommage des constantes !
Conversion de type
modifierEn Java, il est possible de modifier le type des variables. Il existe deux manières de réaliser cette opération :
- une conversion implicite : la modification est réalisée automatiquement par le compilateur, si la conversion du type A vers le type B peut se faire sans perte quelle que soit la valeur du type A ;
- une conversion explicite via l'opérateur cast sous la forme (type_souhaité)variable est nécessaire. Par exemple
{
int x = (int)Math.PI;
}
Variables et classes
modifierLes types de variables ne sont pas des classes, il est aisé de les confondre mais les conventions habituelles d'écritures permettent de les distinguer. Les types de variables sont toujours écrits en minuscules, par contre les classes ont en principe leur premier caractère en majuscule. Aussi lorsque vous rencontrez un Int, ce n’est pas un type de base mais bien une classe en effet les variables peuvent être encapsulées, et Java fournit pour tous[1] les types de variables des classes d'encapsulage appelées wrappers (paquetages).
Ceci peut être utile dans certains cas pour bénéficier de certaines caractéristiques de la classe mère Object. Par exemple, la pose d'un verrou de synchronisation (instruction synchronized) ne peut se faire que sur un objet.
Références
modifier[html] • [licence Copyright] • (en) • lien vers le document • Information sur les types primitifs
Opérations
Les opérations que l’on peut effectuer sur les variables sont nombreuses. Cependant la première chose à savoir est qu’il n'est possible d'effectuer qu'une seule opération sur une variable qui n'a pas été initialisée : lui donner une valeur grâce au signe = comme dans l'exemple du dessus. Voyons maintenant une liste des opérateurs.
Opérateurs de calcul
modifierLes opérateurs de calcul sont :
- + Addition de deux valeurs
- - Soustraction de deux valeurs
- * Multiplication de deux valeurs
- / Division de deux valeurs
- % Applique le modulo (reste de la division euclidienne)
Remarque : Lorsque que l’on utilise des int avec l'opérateur /, on obtiendra un int et non pas un float ni un double. Le résultat est donc tronqué.
Opérateurs logiques
modifierLes opérateurs logiques utilisables sur des booléens sont :
- && ET logique
- || OU logique
- ! NEGATION logique
Opérateurs binaires
modifierLes opérateurs binaires utilisables sur des entiers (int) sont :
- & ET binaire
- | OU binaire inclusif
- ^ OU binaire exclusif
- ~ NEGATION binaire
- << décalage gauche de bits
- >> décalage droit de bits
- >>> décalage droit de bits; aucun changement du bit signe.
Opérateurs d'assignation
modifierLes opérateurs d'assignation permettent de simplifier les expressions en considérant la variable de gauche comme étant le premier nombre de l'opération mais aussi la variable dans laquelle il faudra mettre le résultat. Les opérateurs d'assignation sont :
- = Affecte une valeur à une variable
- += Addition
- -= Soustraction
- *= Multiplication
- /= Division
- %= Modulo
- &= ET logique et binaire
- |= OU logique et binaire
Exemple : Si l’on a x=4 et que l’on fait x+=3, alors x vaudra 7. Ceci est la même chose avec tous ces opérateurs d'assignation.
Opérateur d'incrémentation
modifierLes opérateurs d'incrémentation sont :
- ++ Ajoute 1 à la variable
- -- Retire 1 à la variable
Ces deux opérateurs ajoutent ou retirent 1 à la variable, et sont placés devant ou après la variable. S'il est devant, l'opérateur modifie la variable avant l’utilisation dans une expression. S'il est après, la variable est changée après son utilisation dans l'expression.
Remarque : Ces opérateurs sont en général très utilisés dans les boucles pour faire des compteurs ou plus particulièrement dans les boucles for pour faire le pas mais tout ceci sera vu dans le chapitre consacré aux différentes structures.
Opérateurs de comparaison
modifierLes opérateurs de comparaison sont :
- == opérateur d'égalité (égal à)
- < opérateur d'infériorité stricte (plus petit que)
- > opérateur de supériorité stricte (plus grand que)
- <= opérateur d'infériorité (plus petit qu'ou égal à)
- >= opérateur de supériorité (plus grand qu'ou égal à)
- != opérateur de différence (différent de)
Remarque : Tous ces opérateurs donnent pour résultat un booléen !
Méthodes
Les méthodes sont les algorithmes codés. Il y a plusieurs mots clés à connaître pour la déclaration des méthodes et ce que nous allons voir.
Première méthode
modifierPour qu'un programme en Java puisse être exécuté, une méthode est absolument indispensable, c’est la méthode main. Elle se déclare toujours de la manière suivante :
public static void main(String[] args){
//Ici se trouve le code a exécuter, par exemple :
System.out.println("Coucou !");
}
Cette petite méthode, une fois exécutée, affichera ici un superbe Coucou ! dans la console. En effet, la méthode System.out.println() permet d'afficher du texte dans la console puis de passer à la ligne. Si vous ne voulez pas aller à la ligne, il faut utiliser la méthode System.out.print().
Il est possible de faire appel à d'autres méthodes dans celle-ci, il n'est donc pas nécessaire de faire tout le programme dans cette méthode, et ce n'est d'ailleurs pas conseillé.
lancer avec des paramètres
modifierLe tableau de chaines de caractères args peut stocker un certain nombre de paramètres lors du lancement. La classe ci-dessous les affiche simplement :
public class Exemple1 {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
La lancer ainsi :
java Exemple1 texte1 texte2 ...
Déclaration d'une méthode
modifierMaintenant que nous avons vu la méthode indispensable à tout programme, nous allons voir plus en détail à quoi correspondent tous ces mots clés. Pour cela déclarons une nouvelle méthode :
public static int somme(int nombre1, int nombre2){
return (nombre1 + nombre2) ;
}
Prenons les mots dans leur ordre d'apparition.
- public : désigne l'accessibilité, ce terme sera vu plus en détail dans le chapitre consacré aux objets, on se contentera donc pour le moment de le mettre dans la déclaration de toute méthode.
- static : désigne son statut, ce terme sera vu aussi dans le chapitre consacré aux objets et donc on le fera aussi apparaître à chaque déclaration de méthode pour le moment.
- int : on reconnaît ici un type de donnée, c’est le type de donnée que la méthode va retourner. Ici, la méthode retournera un entier. Une méthode ne peut retourner qu'une seule chose, et il ne sera d'ailleurs pas accepté par le compilateur de trouver plusieurs fois le mot return dans une méthode !
- somme : correspond au nom de ma méthode. Par convention, les noms de méthode commence par une minuscule et prennent une majuscule à chaque nouveau mot. Ainsi, si l’on avait appelé notre méthode sommeDeDeuxEntiers, il aurait fallu l'écrire ainsi et non pas SommeDeDeuxEntiers et encore moins Sommededeuxentiers.
- Dans la parenthèse : ce sont les arguments en entrée de la méthode, on a donc besoin ici de deux entiers pour utiliser cette méthode.
- return : permet de retourner quelque chose, le résultat retourné doit correspondre à ce qui est déclaré en même temps que la méthode.
Utiliser des méthodes
modifierMaintenant que l’on a vu comment déclarer une méthode ainsi que la méthode nécessaire à l'exécution de notre programme, on va voir comment utiliser notre méthode somme.
public class Exemple2 {
public static void main(String[] args){
public static int unEntier ;
//Je déclare une variable.
unEntier = somme(4, 5);
//Je donne une valeur à unEntier en utilisant la méthode somme(int,int)
//qui retourne un entier.
System.out.println("unEntier vaut donc : " + unEntier) ;
//J'affiche dans la console la valeur de unEntier.
}
}
Si l’on souhaite exécuter ce programme simple, il faut copier ceci dans un éditeur de texte et sauvegarder le fichier sous le nom Exemple.java (la majuscule est nécessaire car le compilateur ne reconnaît que les noms de fichiers commençant par une majuscule). Dans la console, il faut se situer dans le répertoire où est sauvegardé le fichier et le compiler grâce à la commande javac Exemple.java, une fois compilé, il faut taper Java Exemple et le programme se lance.
À propos des classes
modifierPour faire un programme, il est nécessaire de créer une classe comme dans l'exemple ci-dessus. Pour cela, il suffit de remplacer le nom Exemple par celui que l’on désire, et de bien le faire commencer par une majuscule, et de sauvegarder le fichier sous le nom de la classe. La vraie utilité des classes sera vue plus en détail dans le chapitre sur les objets.
Arrondir les nombres
modifierPar convention on affiche généralement les nombres avec deux chiffres après la virgule, la méthode Math.round
permet cela[1] :
import java.math.BigDecimal;
public class Arrondi {
public static void main(String[] args) {
BigDecimal nombre1 = null;
for (int i = 0; i < args.length; i++) {
nombre1 = new BigDecimal(Float.valueOf(args[i])).setScale(2, BigDecimal.ROUND_DOWN);
System.out.println(nombre1);
}
}
}
Elle se lance avec un nombre indéfini de paramètre, par exemple :
java Arrondi 1 3.14159
donne :
1.00 3.14
Références
modifier
Boucles et structures conditionnelles
Comme la quasi-totalité des langages de développement orienté objet, Java propose un ensemble d'instructions qui permettent d'organiser et de structurer les traitements. L'usage de ces instructions est similaire à celui rencontré dans leur équivalent dans d'autres langages.
Les boucles
modifierBoucle while
modifierwhile (boolean) {
...// Code à exécuter dans la boucle
}
Le code est exécuté tant que le booléen est vrai. Si avant l'instruction while, le booléen est faux, alors le code de la boucle ne sera jamais exécuté.
Ne pas mettre de ; après l'instruction sinon le corps de la boucle ne sera jamais exécuté. |
Remarque : ce genre de boucle est utilisée lorsque l’on ne sait pas à l'avance le nombre exact de fois que la boucle devra s'exécuter notamment lors de l’utilisation de paramètres définis par l'utilisateur à l'exécution du programme.
Boucle do...while
modifierdo {
...//Code à exécuter dans la boucle
} while (boolean);
Les boucles do...while sont des variantes des boucles while. Leur particularité réside dans le fait que la condition est testée après la première exécution de la boucle. Le code est exécuté tant que la condition est satisfaite et est exécuté au moins une fois.
Exemple de code utilisant la boucle do..while :
class BoucleDo {
public static void main(String arg[]) {
int x = 1 ;
do {
System.out.println("Le système boucle ; pour " + x) ;
++x;
} while (x <= 100);
}
}
Boucle for
modifierfor (initialisation; condition; modification) {
...//Code à exécuter dans la boucle
}
Les boucles for testent une condition et exécutent le bout de code attaché à la boucle tant que la condition est remplie.
Remarque : les boucles for sont le plus souvent utilisées lorsque l’on sait combien de fois on souhaite exécuter le bout de code attaché à la boucle.
Boucle for each
modifierIl existe une variante de la boucle for, la boucle for each qui permet de parcourir une collection.
for (MonType mon_objet : ma_collection) {
mon_objet.ma_methode();
...//Code à exécuter dans la boucle
}
Cette boucle se lit : "Pour chaque objet mon_objet
du type MonType
de la collection ma_collection
alors... "
Les branchements conditionnels
modifierLa condition if...else
modifierLes conditions utilisent des données booléennes, true ou false. Elles vérifient si une condition est remplie. Si oui, elles effectuent un bout de code prédéfini, sinon elles exécutent un autre bout de code prédéfini ou passent directement au reste du programme. Elles ont la forme if...else ....
if (boolean) {
...//Code à exécuter dans la condition
}
else if (boolean) {
...//Code à exécuter si la première condition est fausse et la deuxième vraie
}
else {
...//Code à exécuter si les précédentes conditions ne sont pas vérifiées
}
Remarque : on peut aussi avoir un conditionnel ne comprenant que la partie if(boolean){...}. Dans ce cas, si la condition est remplie, le code entre accolades sera exécuté, sinon, il ne le sera pas et le programme passe à la suite du code. Ainsi, il n’est pas nécessaire de faire apparaître un else s'il n'y a rien à exécuter si la condition n’est pas remplie.
La condition switch...case
modifierLes conditions switch...case remplacent les conditions if..else if..else quand le nombre de else if est trop important. Elles sont en effet plus rapides à écrire.
On ne peut utiliser switch...case qu'avec les types primitifs d’une taille maximum de 32 bits(byte, short, int, char) et les enum (Java 5). Si une instruction case ne contient pas de break alors les traitements associés au case suivant sont exécutés.
Il est possible d'imbriquer des switch.
switch(expression) {
case constant1 :
instruction1;
instruction2;
....
break;
case constant2 :
....
default :
....
}
Remarque : le dernier cas marqué par la présence de default, représentant bien entendu le cas par défaut au cas où expression ne corresponde à aucun des case, n’est pas obligatoire si l’on peut s'assurer qu' expression correspondra toujours à l'un des case.
Les débranchements
modifier- Break
Il permet de quitter une boucle ou un branchement. Utilisable dans tous les contrôles et flot.
- Continue
S'utilise dans une boucle pour passer à l'itération suivante.
break et continue peuvent s'exécuter avec des blocs nommés. Il est possible de préciser une étiquette pour indiquer le point de retour lors de la fin du traitement déclenché dans le break.
Une étiquette est un nom suivi d’un des deux points qui définit le début d’une instruction.
La condition Ternaire
modifierLa condition ternaire utilise également des données booléennes, true ou false. Cette condition est une sorte de "condensé" de la structure if/else.
variable = (condition) ? instruction 1 : instruction 2 ;
Si la condition (boolean) est vraie, c’est l'instruction1 située après le point d'interrogation (?) qui est effectuée; si elle est fausse, c’est l'instruction2 située après les deux points (:) qui est effectuée. La condition doit être entre parenthèses obligatoirement.
int nombre =(boolean)? 1 : 2 ;
Ainsi : nombre est égal à 1 si la condition est vraie, à 2 si la condition est fausse.
Il est également possible d'imbriquer des conditions ternaires:
variable = (condition) ? ((autre condition)? instruction1 :instruction2):instruction3 ;
Et ainsi de suite... Il n'est cependant pas conseillé de faire un usage trop systématique de cette condition, trop peu lisible.
Tableaux
Tableaux
modifierPratiquement tous les langages gèrent les tableaux. Utiliser des tableaux en C ou C++ est dangereux car ces tableaux ne sont que des blocs de mémoire. Si un programme accède à un tableau en dehors de son bloc mémoire, ou s'il utilise la mémoire avant initialisation (erreurs de programmation fréquentes) les résultats seront imprévisibles.
Un des principaux objectifs de Java est la sécurité, aussi, un grand nombre des problèmes dont souffrent C et C++ ne sont pas rejetées sous Java. On est assuré qu'un tableau Java est initialisé et qu’il ne peut être accessible au delà de ses bornes. La vérification des bornes se fait au prix d’un petit excédent de mémoire pour chaque tableau ainsi que la vérification de l'index lors de l'exécution, mais on suppose que le gain de sécurité et en productivité vaut la dépense.
Quand on crée un tableau d'objet, on crée en réalité un tableau de références, et chacune de ces références est automatiquement initialisée à une valeur particulière avec son propre mot clé : null. Quand Java voit null, il reconnaît que la référence en question ne pointe pas vers un objet. Il faut affecter un objet à chaque référence avant de l’utiliser et si on essaye d’utiliser une référence encore null, le problème sera signalé lors de l'exécution. Ainsi, les erreurs typiques sur les tableaux sont évitées en Java.
On peut aussi créer des tableaux de variables de types primitif. À nouveau, le compilateur garantit l'initialisation car il met à zéro la mémoire utilisée par ces tableaux.
Les tableaux se distinguent des autres conteneurs sur deux points : l'efficacité et le type. Un tableau constitue la manière la plus efficace que propose Java pour stocker et accéder aléatoirement à une séquence d'objets (en fait de référence sur ces objets). Un tableau est une simple séquence linéaire, ce qui rend l'accès aux éléments extrêmement rapide; mais cette rapidité se paye : la taille d’un tableau est fixée lors de la création et ne peut plus être changé pendant toute la durée de sa vie. Une solution est de créer un nouveau tableau et de déplacer toutes les références de l'ancien tableau vers le nouveau.
Déclaration de tableaux
modifierLa création de tableaux en Java se fait à peu près de la même manière que la création de variables. Prenons l'exemple suivant :
String[] monTableau ;
//On a créé un tableau de chaînes de caractères mais ce tableau n’est pas encore utilisable car il n'a pas de taille !
monTableau = new String[nombreDObjets] ;
//Il est maintenant utilisable et indexé de 0 à nombreDObjets-1.
//On peut toutefois compresser l'écriture en mettant directement :
String[] monTableau2 = new String[nombreDObjets] ;
//On peut aussi le remplir directement :
String[] monTableau3 = {"chaine 1", "chaine 2", "chaine 3"};
Il est possible de faire des tableaux de tout type de données, y compris les types que l’on crée soit même (mais nous verrons ça dans le chapitre sur les objets). Il est aussi possible de créer des tableaux de tableaux et plus encore. Par exemple :
int[][] tableauDeTableau = new int[5][4] ;
//Ainsi tableauDeTableau est en réalité une matrice de taille 5x4.
//Ceci peut être très utile pour la manipulation de grille par exemple.
boolean[][][] pave = new boolean[3][4][5] ;
//On peut aussi créer des tableaux à plus de deux dimensions,
//on n'est en fait pas limité dans la dimension de notre tableau
Remarque : un tableau ne peut contenir qu'un seul type de donnée. Ainsi, il est impossible de stocker des entiers dans un tableau qui a été déclaré comme contenant des chaînes de caractères.
Utilisation de tableaux
modifierMaintenant que l’on sait déclarer un tableau, il peut être intéressant de savoir comment s'en servir. Plusieurs choses sont à savoir :
- la première est comment utiliser les objets présents dans le tableau
- la deuxième est comment utiliser de manière pratique les tableaux
int[] monTableau = new int[5] ;
//Ici on crée un tableau de 5 entier, les indices du tableau
//vont donc de 0 à 4.
for(int i=0 ; i<monTableau.length ; ++i){
monTableau[i] = i + 1 ;
}
Ici, on utilise une boucle for pour parcourir l’ensemble du tableau. On utilisera le plus souvent ce genre de boucle sur les tableaux car leur taille est définie lors de la déclaration et donc on connait leur taille. Pour être sûr de ne pas se tromper sur la taille du tableau, ce qui nous ferait sortir du tableau lors de l'exécution de la boucle, on utilise ici la méthode length qui est valable sur tous les tableaux de données de type de base.
Si l’on crée un tableau d'objets qui ne sont pas d’un type de base, il faudrait alors utiliser la méthode length() héritée de Object mais on reverra ceci plus en détail dans la partie destinée aux objets.
monTableau[i] désigne le i+1 ième entier de monTableau
Classes et objets
Introduction
modifierLe terme orienté objet souvent lié au langage Java vient d’une part du fait que l’on peut :
- Créer des objets
- Libérer des objets non utilisés à l’aide d’un ramasse-miettes
Un objet est une instance d’une classe, qui est l’outil fondamental de programmation en Java. Une classe peut aussi être considérée comme une description de ce qu’il faut faire pour créer un objet. Les classes sont composées de méthodes et d’attributs qui peuvent être public, private ou protected.
Les différents mots clés concernant l'accessibilité sont les suivants :
- Aucun mot clé: accessible par les classes du même paquetage ou package ;
- Public: accessible par toutes les classes ;
- Protected: accessibles par toutes les classes héritées et les classes du même paquetage, inaccessibles par les autres ;
- Private: inaccessible par toute autre classes.
Ces termes sont utilisables aussi bien sur les méthodes que sur les variables.
Le terme static permet aussi de spécifier des variables de classe ou des méthodes de classe.
Créer une classe permettant de créer des objets
modifierLa première étape pour créer de nouveaux objets est de créer une nouvelle classe de façon particulière. C’est ce que l’on va voir avec l'exemple de la classe Point.
public class Point{
public static double dimension = 2 ;
//Variable de classe
private double x ;
private double y ;
//Variables d'instance
public Point(){
this(0,0) ;
}
//Constructeur par défaut
public Point(double x , double y){
this.setX(x) ;
this.setY(y) ;
}
//Constructeur avec argument
public double getX(){
return this.x ;
}
public void setX(double x){
this.x = x ;
}
//Accesseurs correspondant à la variable x.
public double getY(){
return this.y ;
}
public void setY(double y){
this.y = y ;
}
//Accesseurs correspondant à la variable y.
public void symetrieSelonX(){
this.y = -this.y;
}
public void symetrieSelonY(){
this.x = -this.x;
}
public static double quelleDimension(){
return dimension ;
}
}
Cet exemple mérite des éclaircissements qui vont être donnés dans la suite.
Variables de classe/d'instance
modifierDans l'exemple de classe que nous avons ici, il apparaît une variable de classe et deux variables d'instance. Quelle est donc la différence entre ces deux types de variables lors de la création d’un objet ?
La variable de classe n'est en rapport avec aucun objet, elle ne dépend d'aucun objet, le plus souvent elle ne sera pas modifiée au cours de l'exécution du programme. Dans notre exemple, elle sera accessible dans la classe directement par son nom et dans d'autres classes par Point.dimension ou par la méthode statique appelée par Point.quelleDimension().
Les variables d'instance servent à représenter l’objet informatiquement. Ainsi, il est possible de représenter tous les objets réels par un ensemble de données de bases. Ceci s’appelle l'agrégation. C’est la méthode la plus utilisée pour créer des objets simples. Ici, notre point est représenté par deux double qui sont dans la réalité ses coordonnées. Ces deux variables sont déclarées private par convention, en effet, on ne souhaite pas que d'autres classes puissent accéder directement à ces données. Chaque instance de l’objet (ici chaque Point) aura des valeurs différentes pour ces variables, elles sont réellement sa représentation, et contrairement aux variables de classes, ce sont bien ces données-là qui seront manipulées lors de l'exécution du programme.
Constructeur
modifierLe constructeur comme son nom l'indique est la méthode qui sert à créer une instance d’un objet. Sa déclaration est particulière puisqu’un constructeur ne retourne rien (on ne peut pas avoir return dans un constructeur). On peut remarquer ici qu’il y a deux constructeurs :
- le constructeur par défaut, sans argument, il se contentera d'appeler le deuxième constructeur avec 0 et 0 en argument.
- le constructeur avec argument qui permet de créer un point avec les coordonnées x et y.
Plusieurs choses nouvelles apparaissent dans ces constructeurs :
- La première, qui n’est pas des plus simples à comprendre, est l'apparition de this. Ce terme est le plus important de la programmation par objet en Java. En effet, ce terme représente la future instance de l'objet. Ainsi this pointe déjà vers une instance de l'objet. La première utilisation que l’on peut remarquer, est celle qui en est faite dans le constructeur avec argument, où les arguments portent le même nom que les variables d'instance mais ces dernières sont différenciées par l'apparition de this devant.
- La deuxième chose importante est le chaînage des constructeurs. Il peut paraître étrange d’avoir plusieurs constructeurs mais ils se différencient parfaitement par leurs arguments, il est donc possible d’avoir toute une panoplie de constructeurs. Le chaînage des constructeurs est donc le fait de faire appel à un constructeur dans un constructeur. On remarque alors que le constructeur par défaut fait appel au constructeur avec argument par this(0,0) avec les arguments 0 et 0.
- La dernière chose est le fait de ne pas faire appel directement aux variables d'instances mais plutôt aux accesseurs. Même si ici ce n’est pas franchement utile, on retiendra quand même cela comme une convention car cela permet de changer de représentation (changer les variables d'instance) sans ne jamais changer les constructeurs. Un exemple sera donné dans la partie consacrée aux accesseurs.
Remarque : il n’est pas obligatoire d’avoir un constructeur pour créer des objets car Java en crée un par défaut. Cependant, ce constructeur par défaut initialisera toutes les variables d'instance à la valeur null quel que soit le type de donnée.
Il est maintenant intéressant de savoir comment utiliser ces constructeurs. Le meilleur moyen de le savoir est de créer quelques points.
Point monPoint = new Point() ;
//La création d'une instance se fait de cette manière, ici on remarque
//que Point est devenu un nouveau type de donnée, on a créé un objet.
//On a utilisé ici le constructeur par défaut, donc monPoint a pour
//coordonnées (0,0).
Point monPoint2 = new Point(2,1) ;
//On a créé ici un point de coordonnées (2,1).
Accesseurs
modifierLes accesseurs sont les méthodes, et d'ailleurs les seules, qui accèdent directement aux variables d'instance. Ainsi, ces méthodes seront utilisées dans les constructeurs, dans les méthodes d'instances, mais aussi dans toute autre méthode qui nécessitera une donnée particulière de notre objet.
Par convention, les accesseurs permettant d'accéder aux valeurs des variables d'instance ont toujours pour nom get + le nom de la variable et les accesseurs permettant de modifier les valeurs des variables d'instance set + le nom de la variable. Ainsi, il est en général très simple d’utiliser un code, même un code qui n’est pas le sien, si ces conventions sont respectées.
Le grand intérêt des accesseurs est de rendre indépendant tout le reste du code de la représentation de l'objet. Pour s'en convaincre, l'exemple des nombres complexes en représentation cartésienne puis en polaire est très bon à faire.
Méthodes de classe/d'instance
modifierLes méthodes de classe et d'instance se différencient exactement de la même manière que les variables de classe ou d'instance. Ainsi, on appelle une méthode de classe (prenons l'exemple de la classe Point) par Point.quelleDimension(). Les méthodes d'instance ne s'appliquent qu’à une instance de classe, il est donc nécessaire de créer au moins un objet pour pouvoir appeler ces méthodes.
Point monPoint = new Point(4,6) ;
//On crée un Point
monPoint.symetrieSelonX() ;
//On appelle la méthode symetrieSelonX() sur l'instance monPoint de Point.
System.out.println("L'abscisse de monPoint est : " + monPoint.getX()) ;
System.out.println("Oracle : L'abscisse de monPoint est : 4") ;
//On remarque que les accesseurs sont appelés comme des méthodes d'instance normales, et
//en effet, c'en sont.
System.out.println("L'ordonnée de monPoint est : " + monPoint.getY()) ;
System.out.println("Oracle : L'ordonnée de monPoint est : -6") ;
On a donc créé une instance à laquelle on a appliqué des méthodes.
Héritage et polymorphisme
Introduction
modifierHéritage
modifierUne classe peut utiliser l'héritage pour prendre la même forme qu'une autre classe.
public class Exemple
{
public Exemple()
{
}
}
class ExempleEnfant extends Exemple
{
public ExempleEnfant()
{
super();
}
}
Par défaut, la classe enfant utilise le constructeur par défaut du parent. Vous pouvez utiliser un autre constructeur avec le mot clé super dans la première phrase du constructeur de l'enfant.
L'interface
modifierLes interfaces sont une collection des méthodes abstract et constantes.
Un objet peut utiliser plusieurs interfaces.
public interface Exemple
{
public static final String MA_CONSTANTE = "Peuh";
public abstract int methode();
}
Polymorphisme
modifierLe polymorphisme est le changement de l'activité d'une classe parent par les sous-classes.
// Exemple du http://fr.wikipedia.org/w/index.php?title=Polymorphisme_(informatique)&oldid=30800612
abstract class Forme {
abstract float aire() ;
}
class Carre extends Forme{
float cote;
float aire() {
return cote * cote;
}
}
class Cercle extends Forme{
float rayon;
float aire() {
return Math.PI*rayon*rayon;
}
}
Aussi, il est possible d’utiliser le polymorphisme avec les classes anonymes.
{
Forme unite = new Forme() {
float aire() {
return 1;
}
}
}
Exceptions
Introduction
modifierPour avoir un programme robuste, il faut gérer les erreurs qui peuvent subvenir lors de l'exécution du programme.
Une erreur ou une exception se produit lorsque les conditions d'exécution sont telles que la poursuite du programme devient impossible ou incorrecte. Par exemple il peut s'agir d'un débordement de tableau, d'un manque de mémoire, d'une division par zéro ou même, comme nous allons le voir par la suite, d'une exception levée par le programmeur.
Cela oblige à écrire de nombreux tests qui n'ont pas de rapport direct avec la tâche principale du programme.
Ce n’est pas toujours facile avec les langages classiques, tel le C où le seul moyen de gérer les exceptions est de retourner des constantes comme 0 ou -1 par une méthode pour signifier que son exécution s'est respectivement déroulée sans ou avec problème...
Java propose une approche très différente :
class Point {
public static final int X_MAX = 1024, Y_MAX = 768;
private int x, y;
public Point (int a, int b) throws Exception {
if (a < 0 || a >= X_MAX || b < 0 || b >= Y_MAX) {
throw new Exception("Coordonnées illégales.");
}
x = a;
y = b;
}
}
Qu'est-ce qu'une exception
modifierC'est un objet de la classe java.lang.Throwable
, classe mère de toutes les erreurs et exceptions. Cette classe a pour sous-classes :
java.lang.Error
dont doivent hériter les erreurs graves qui causent l'arrêt du programme comme par exemple la classeOutOfMemoryError
,java.lang.Exception
dont doivent hériter les erreurs qui doivent impérativement être traitées ou capturées comme par exemple la classeFileNotFoundException
,java.lang.RuntimeException
, qui hérite dejava.lang.Exception
, et dont doivent hériter les erreurs qui peuvent ne pas être traitées ou capturées, comme par exemple les classesNullPointerException
,NumberFormatException
ou encoreArrayIndexOutOfBoundsException
.
Capturer une exception
modifierLorsqu'une exception est lancée, elle se propage d'une méthode à la méthode appelante jusqu'à être capturée. Si elle ne l'est pas, le programme s'arrête et le contenu de la pile des méthodes traversées est indiqué à l'utilisateur.
Syntaxe d'une interception :
try {
bloc_1
} catch(type_exception_1 arg_1) {
bloc_2
} catch(type_exception_2 arg_2) {
bloc_3
}...
} finally {
bloc_N
}
Si une erreur survient dans le bloc d'instructions no 1, l'interpréteur le quitte immédiatement et une exception est levée. Comme nous nous trouvons dans un bloc try/catch
elle sera peut être attrapée par le catch
correspondant, auquel cas son bloc d'instructions sera exécuté. Si aucun des catch
présents ne l'attrapent, l'erreur se propage à la méthode appelante et ainsi de suite. Dans tous les cas le bloc finally
(facultatif) est exécuté, même en présence d'un return
dans le bloc no 1 exécuté sans erreur.
Depuis la version 7 de Java, il est possible d'utiliser le catch de multiple Exceptions :
try {
...
} catch(IOException|SQLException ex) {
.....
}
Un exemple continuant celui de l'introduction :
try {
Point p = new Point(u, v);
} catch(Exception e) {
System.out.println("Problème avec les coordonnées du point :");
System.out.println(e.getMessage());
e.printStackTrace();
}
À noter que de nombreuses méthodes de la bibliothèque Java (l'API Java) peuvent générer des exceptions. C’est le cas par exemple de la méthode de classe int Integer.parseInt(String)
qui a pour fonction de convertir une chaîne de caractères en un entier (par exemple "123" en l'entier 123). Si la chaîne ne contient pas un nombre, la méthode lève une NumberFormatException
. Comme cette exception n'a pas obligation à être interceptée (cf. #Qu'est-ce qu'une exception), il n’est pas impératif, quoique conseillé, de placer chaque appel à int Integer.parseInt(String)
au sein d'un bloc try/catch
.
Méthodes de l’objet Exception
modifier- printStackTrace() : affiche l'état de la pile lors de la remontée de l'exception. Utile pour trouver les causes de celle-ci.
Lancer une exception
modifierUne exception peut être lancée via la syntaxe suivante :
throw exception;
où exception
est une expression dont la valeur doit être un objet de type Throwable
.
Si une méthode est susceptible de lancer une exception de type T
ou U
, elle doit :
- soit l'attraper via un bloc
try/catch
adéquat, - soit déclarer qu'elle est susceptible de laisser échapper des exceptions via l’expression
throws T, U
placée en fin d'en-tête de méthode (cf. l'en-tête du constructeur de la classe Point ici et là).
Créer son propre type d'exception
modifierOn le peut en héritant de la class Exception
:
class CoordonneesIllegalesException extends Exception {
public CoordonneesIllegalesException () {
super("Coordonnées illégales.");
}
public CoordonneesIllegalesException (String msg) {
super(msg);
}
public CoordonneesIllegalesException (Throwable cause) {
super(cause);
}
public CoordonneesIllegalesException (String msg, Throwable cause) {
super(msg, cause);
}
}
Le constructeur de la classe Point de l’exemple introductif peut alors s'écrire :
public Point (int a, int b) throws CoordonneesIllegalesException {
if (a < 0 || a >= X_MAX || b < 0 || b >= Y_MAX) {
throw new CoordonneesIllegalesException();
}
x = a;
y = b;
}
Exceptions courantes
modifier
Gestion de fichiers
Créer un fichier
modifierimport java.io.*;
public class NouveauFichier {
public static void main(String args[]) throws Exception {
FileWriter fw1 = new FileWriter("fichier1.txt"); // Écrase le fichier s'il existe déjà
BufferedWriter bw1 = new BufferedWriter(fw1);
bw1.write("Début du texte 1");
bw1.close();
}
}
Lancer deux fois cette classe effacera le résultat de la première dans le fichier résultat. Pour l'éviter, utiliser new FileWriter("fichier1.txt", true) .
|
Lire
modifierPour lire le fichier créé ci-dessus :
import java.io.*;
public class LireFichier {
public static void main(String[] args) {
File fichier = new File("fichier1.txt");
int car;
StringBuffer contenu = new StringBuffer("");
FileInputStream ftemp = null;
try {
ftemp = new FileInputStream(fichier);
while( (car = ftemp.read()) != -1)
contenu.append((char)car);
ftemp.close();
}
catch(FileNotFoundException e) {
System.out.println("Fichier introuvable");
}
catch(IOException ioe) {
System.out.println("Exception " + ioe);
}
System.out.println(contenu);
}
}
Références
modifierVoir aussi
modifier- Programmation Java/Entrées Sorties sur Wikilivres
- Gestion des fichiers .xml sur Wikilivres
Interfaces graphiques
Interfaces
modifierDifférents packages peuvent assurer l'interface graphique :
- AWT.
- SWT.
- Swing, voir aussi le wikilivre sur Swing.
- JavaFX remplaçant Swing dans les versions récentes de Java.
Locode
modifierCeci est un petit programme qui télécharge la liste des codes de localisation de la Commission économique des Nations Unies pour l'Europe (UNECE) et affiche la table des codes de localisation avec une classe Tablesorter spécial publié par Oracle. La trieuse de table peut trier par plusieurs lignes (maintenez la touche CTRL et sélectionner une autre ligne en cliquant sur l'en-tête pour trier par un deuxième ou troisième rangée).
Code source
modifierpackage org.wikiversity.java_tutorial;
import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import misc.oracle.components.TableSorter; // http://vsrs.svn.sourceforge.net/viewvc/vsrs/src/vsrs/ui/components/TableSorter.java
public class Locode
{
// Une constante pour la page internet.
public final static String LOCODE_URL = "http://live.unece.org/fileadmin/DAM/cefact/locode/loc111csv.zip";
// Un tableau pour la largeur des colonnes de la table.
private final static int[] WIDTH = {
50, 50, 50, 250, 250, 50, 120, 50, 120, 50, 250, 50
};
/**
* Le programme télécharge une liste des codes de localisation de la
* commission économique pour l'Europe.
* La principale méthode est toujours la première méthode appelée dans
* un programme et appelle toutes les autres méthodes.
*
* @see http://fr.wikipedia.org/wiki/Commission_économique_pour_l'Europe
* @param args
*/
public static void main (String[] args)
{
// En programmation orientée objet, une instance d'une classe est un objet
// avec un comportement correspondant à cette classe et un état initial.
// Le comportement de la classe est définie par ses méthodes.
new Locode ().run (args); // Créer une instance de la classe de Locode
}
/**
* Dans ce programme, la seule méthode appelée par
* les méthode «main» est «run».
* «run» est une méthode d'instance (sans le mot clé «static»)
*/
private void run (String[] args)
{
// Créer une instance de la classe de File.
File locodeArchive = file ("~/.un/locode/loc111csv.zip");
// Un appel à la méthode «mkdirs» dans une autre classe crée un dossier pour le fichier.
locodeArchive.getParentFile ().mkdirs ();
// Un appel à la méthode «downloadArchive» dans cette classe
// télécharge l'archive de la UNECE.
downloadArchive (locodeArchive);
// Test avec «IF», si l'archive existe maintenant
if (!locodeArchive.exists ())
{
// Ces deux déclarations ne sont exécutées que si l'archive n'existe pas.
System.err.println ("Archive " + LOCODE_URL + " is not available.");
// Mettre fin au programme: le programme a échoué
System.exit (1);
}
// Un appel à la méthode «readDataFromArchive» dans cette classe
// lit les données de l'archive.
DefaultTableModel model = readDataFromArchive (locodeArchive);
// Demandez à l'DefaultTableModel classe pour le nombre de lignes
// lues avec le méthode «getRowCount» et d'imprimer la valeur.
System.out.println (model.getRowCount () + " rows.");
// Un appel à la méthode «displayTable» dans cette classe
// affiche le tableau à l'écran.
displayTable (model);
}
/**
* Affiche le tableau à l'écran.
*
* @param model
*/
private void displayTable (DefaultTableModel model)
{
JFrame frame = new JFrame ("UN Location Codes");
frame.setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);
frame.setLayout (new BorderLayout ());
frame.setSize (1024, 500);
JTable table = new JTable ();
JScrollPane js = new JScrollPane (table);
js.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
js.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
frame.add (js, BorderLayout.CENTER);
table.getTableHeader ().setReorderingAllowed (true);
table.getTableHeader ().setResizingAllowed (true);
TableSorter sorter = new TableSorter (model);
table.setModel (sorter);
sorter.setTableHeader (table.getTableHeader ());
for (int i=0; i<12; i++)
table.addColumn (new TableColumn (i, WIDTH[i]));
frame.setVisible (true);
}
private final static File file (String path)
{
if (path.charAt (0) == '~')
path = System.getProperty ("user.home") + path.substring (1);
return new File (path);
}
/**
* Télécharge l'archive de la UNECE.
*
* @param locodeArchive
*/
private void downloadArchive (File locodeArchive)
{
long lastModified = locodeArchive.lastModified ();
try {
URL url = new URL (LOCODE_URL);
URLConnection c = url.openConnection ();
if (c.getLastModified () <= lastModified)
return;
byte buffer[] = new byte[0xffff];
OutputStream os = null;
InputStream is = c.getInputStream ();
try
{
int bytesRead;
os = new FileOutputStream (locodeArchive);
for (;;)
{
if ((bytesRead = is.read (buffer)) == -1)
break;
os.write (buffer, 0, bytesRead);
System.out.print (".");
System.out.flush ();
}
System.out.println ();
}
catch (Exception ex) {
closeSilently (os);
closeSilently (is);
}
}
catch (Exception ex) {
System.err.println ("Failed to download file: " + ex);
}
}
/**
* Lit les données de l'archive.
*
* @param inputFile
* @return
*/
private DefaultTableModel readDataFromArchive (File inputFile)
{
DefaultTableModel model = new DefaultTableModel ();
Vector<Object> v = model.getDataVector ();
InputStream is = null;
JarFile file = null;
BufferedReader br;
String line, nextLine;
Object[] row;
try
{
// Créer une instance de la classe JarFile (jar fichier)
// pour le archive.
file = new JarFile (inputFile);
// Créer une énumération du contenu de l'archive
// et itérer sur l'énumération.
for (Enumeration<JarEntry> e = file.entries (); e.hasMoreElements (); )
{
// Créer une instance de la classe JarEntry (jar entrée)
// pour le archive.
JarEntry je = (JarEntry) e.nextElement ();
// Le «IF» tests si le nom du fichier se termine par "csv".
if (!je.getName ().toLowerCase ().endsWith (".csv"))
continue;
// Imprimer le nom de l'entrée.
System.out.println ("Reading: " + je.getName ());
// Demande une instance de la classe InputStream.
is = file.getInputStream (je);
// Créer une instance de la classe BufferedReader.
br = new BufferedReader (new InputStreamReader (is));
// Un bloc avec un nom permet référer à ce bloc dans
// une instruction break; l'instruction termine l'exécution
// de ce bloc et le programme se poursuit après la fin du bloc.
loop:
while ((line = br.readLine ()) != null)
{
// Un appel à la méthode «csvSplit».
row = csvSplit (line);
while (row.length < 12)
{
// Affiche un message indiquant que la ligne
// ne contient pas suffisamment de données
System.out.println ("Unexpected number of fields: " + row.length + ", reading next line for more input.");
// S'il n'ya pas d'entrée pour lire plus l'instruction «IF»
// se termine le bloc. Sans le nom il serait tout simplement
// mettre fin à la boucle while.
if ((nextLine = br.readLine ()) == null)
break loop;
// Ajoute les données de la ligne précédente à la ligne actuelle.
line += nextLine;
// Un appel à la méthode «csvSplit».
row = csvSplit (line);
// Un appel à la méthode «printRow» (ligne Imprimez)
printRow (line, row);
}
// Ajoute les ligne avec un appel à la méthode "addElement"
// à la classe Vector (vecteur, un type de tableau).
v.addElement (new Vector<Object> (Arrays.asList (row)));
}
}
}
catch (Exception ex) {
closeSilently ((Closeable) file);
closeSilently (is);
}
return model;
}
private void printRow (String line, Object[] row)
{
System.out.println ("---- " + line);
for (int i=0; i<row.length; i++)
{
System.out.println ("[" + i + "]: " + row[i]);
}
}
private void closeSilently (Closeable c)
{
if (c != null) {
try {
c.close ();
}
catch (IOException ex) { /* intentionally ignored */ }
}
}
private final static String[] STRING_ARRAY = new String[0];
/**
* La méthode divise une chaîne en un tableau de chaînes.
*
* @param s
* @return
*/
private final static String[] csvSplit (String s)
{
ArrayList<String> a = new ArrayList<String> ();
char[] chars = s.toCharArray ();
int p1 = 0, p2;
for (;;)
{
if ((p2 = csvIndexOf (chars, p1)) == -1) {
a.add (trimQuotes (s.substring (p1)));
break;
}
String sub = s.substring (p1, p2);
p1 = p2 + 1;
a.add (trimQuotes (sub));
}
if (a.size () == 0)
return STRING_ARRAY;
return (String[]) a.toArray (STRING_ARRAY);
}
/**
* La méthode supprime guillemets au début et à la fin d'une chaîne.
*
* @param s
* @return
*/
private final static String trimQuotes (String s)
{
if (s.startsWith ("\"") && s.endsWith ("\"")) {
return s.substring (1, s.length () - 1);
}
return s;
}
/**
* La méthode itère sur les caractères d'une chaîne commençant
* par le caractère à la position «pos» et retourne la virgule
* suivant qui n’est pas entre guillemets.
*
* @param str
* @param pos
* @return
*/
private final static int csvIndexOf (char[] str, int pos)
{
boolean notInsideQuote = true;
for (int i=pos; i<str.length; i++)
{
if (str[i] == '"')
notInsideQuote = !notInsideQuote;
if (str[i] == ',' && notInsideQuote)
return i;
}
return -1;
}
}
Exercices
modifier- Améliorer le modèle de table et le rendu des cellules du tableau. Que peut-il être amélioré ?
- Ajouter un filtre qui permet de filtrer la table avec des expressions rationnelles.
- Affichage des codes d'emplacement sur un globe ou de permettre de sélectionner des régions sur une carte.
Réflexion
La réflexion en Java permet de passer outre certaines sécurités du langage, mais également de faire de la programmation dynamique sur les classes. Elle est particulièrement utilisée dans les systèmes d'extension (plugins) pour charger une classe ou accéder à un membre de la classe de manière dynamique.
GFDL | Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans texte de dernière page de couverture. |