Le type de données String (chaîne de caractère) n'est pas un type élémentaires en Java, c'est une classe. Donc une chaîne de type string est un objet qui n'est utilisable qu'à travers les méthodes de la classe String.
Pour accéder à la classe String et à toutes ses méthodes, vous devez mettre avant la déclaration de votre classe l'instruction d'importation de package suivante :
import java.lang.String ;
Un littéral de chaîne est une suite de caractères
entre guillemets : " abcdef " est un exemple de littéral de
String.
Etant donné que cette classe est très utilisée les
variables de type String bénéficient d'un statut d'utilisation
aussi souple que celui des autres types élémentaires. On peut
les considérer comme des listes de caractères numérotés
de 0 à n-1 (si n figure le nombre de caractères de la chaîne).
Déclaration d'une variable String
String str1;
Déclaration d'une variable String avec initialisation
String str1 = " abcdef ";
Ou
String str1 = new String("abcdef ");
On accède à la longueur d'une chaîne par la méthode :
int length( )
String str1 = "abcdef";
int longueur;
longueur = str1.length( ); // ici longueur vaut 5
Toutefois les String de Java sont moins conviviales en utilisation
que les string de pascal ou celles de C#, il appartient au programmeur
d'écrire lui-même ses méthodes d'insertion, modification
et suppression.
Toutes les autres manipulations sur des objets String nécessitent
l'emploi de méthodes de la classe String. Nous donnons quelques exemples
d'utilisation de méthode classique sur les String.
Le type String possède des méthodes classiques d'extraction,
de concaténation, de changement de casse, etc.
Concaténation de deux chaînes
Un opérateur ou une méthode
Opérateur : + sur les chaînes
ou
Méthode : String concat(String s)
Les deux écritures ci-dessous sont donc équivalentes en Java :
str3 = str1+str2 str3 = str1.concat(str2)
String str1,str2,str3;
str1="bon";
str2="jour";
str3=str1+str2;
On accède à un caractère de rang fixé d'une chaîne par la méthode :
char charAt(int rang)
Il est possible d'accéder en lecture seulement à chaque caractère d'une chaîne, mais qu'il est impossible de modifier un caractère directement dans une chaîne.
String ch1 = "abcdefghijk";
char car = ch1.charAt(4);
// ici la variable car contient la lettre 'e'
position d'une sous-chaîne à l'intérieur d'une chaîne donnée :
méthode :
int indexOf ( String ssch)
String ch1 = " abcdef " , ssch="cde";
int rang ;
rang = ch1.indexOf ( ssch );
// ici la variable rang vaut 2'
Les String Java ne peuvent pas être considérées
comme des tableaux de caractères, il est nécessaire, si l'on
souhaite se servir d'une String, d'utiliser la méthode
toCharArray pour convertir la chaîne en un tableau de caractères
contenant tous les caractères de la chaîne.
Enfin, attention ces méthodes de manipulation d'une chaîne ne
modifient pas la chaîne objet qui invoque la méthode mais renvoient
un autre objet de chaîne différent. Ce nouvel objet est obtenu
après action de la méthode sur l'objet initial.
Soient les quatre lignes de programme suivantes :
String str1 = "abcdef" ;
char [ ] tCarac ;
tCarac = str1.toCharArray( ) ;
tCarac = "abcdefghijk".toCharArray( );
Illustrons ci-dessous ce qui se passe relativement aux objets créés :
String str1 = "abcdef" ;
str1 référence un objet de chaîne.
char [ ] tCarac ;
tCarac = str1.toCharArray( ) ;
tCarac référence un objet de tableau à 6 éléments.
tCarac = "abcdefghijk".toCharArray( );
tCarac référence maintenant un nouvel objet de tableau à 11 éléments, l'objet précédent est perdu (éligible au Garbage collector)
L'exemple précédent sur la concaténation ne permet pas de voir que l'opérateur + ou la méthode concat renvoie réellement un nouvel objet en particulier lors de l'écriture des quatre lignes suivantes :
String str1,str2;
str1="bon";
str2="jour";
str1=str1+str2;
Illustrons ici aussi ce qui se passe relativement aux objets créés
:
String str1,str2;
str1="bon";
str2="jour";
str1=str1+str2;
un nouvel objet de chaîne a été créé et str1 "pointe" maintenant vers lui.
Opérateurs d'égalité de String
- L'opérateur d'égalité = = , détermine si deux objets String spécifiés ont la même référence et non la même valeur, il ne se comporte pas en Java comme sur des éléments de type de base (int, char,...)
String a , b ;
(a = = b ) renvoie true si les variables a et b référencent chacune le même objet de chaîne sinon il renvoie false.
- La méthode boolean equals(Object s) teste si deux chaînes n'ayant pas la même référence ont la même valeur.
String a , b ;
a.equals ( b ) renvoie true si les variables a et b ont la même valeur sinon il renvoie false.
En d'autres termes si nous avons deux variables de String ch1 et ch2, que
nous ayons écrit ch1 = "abcdef"; et plus
loin ch2 = "abcdef"; les variables ch1 et ch2
n'ont pas la même référence mais ont la même valeur
(valeur = "abcdef").
Voici un morceau de programme qui permet de tester l'opérateur d'égalité
= = et la méthode equals :
String s1,s2,s3,ch;
ch = "abcdef";
s1 = ch;
s2 = "abcdef";
s3 = new String("abcdef".toCharArray(
));
System.out.println("s1="+s1);
System.out.println ("s2="+s2);
System.out.println ("s3="+s3);
System.out.println ("ch="+ch);
if( s1 == ch ) System.out.println ("s1=ch");
else System.out.println ("s1<>ch");
if( s1 == s3 ) System.out.println ("s1=s3");
else System.out.println ("s1<>s3");
if( s1.equals(s2) ) System.out.println ("s1 même val. que s2");
else System.out.println ("s1 différent de s2");
if( s1.equals(s3) ) System.out.println ("s1 même val. que s3");
else System.out.println ("s1 différent de s3");
if( s1.equals(ch) ) System.out.println ("s1 même val. que ch");
else System.out.println ("s1 différent de ch");
Après exécution on obtient :
ATTENTION
En fait, Java a un problème de cohérence avec les littéraux de String. Le morceau de programme ci-dessous montre cinq évaluations équivalentes de la String s2 qui contient après l'affectation la chaîne "abcdef", puis deux tests d'égalité utilisant l'opérateur = = . Nous avons mis en commentaire, après chacune des cinq affectations, le résultat des deux tests :
String ch;
ch = "abcdef" ;
String s2,s4="abc" ;
s2 = s4.concat("def") ; /* après tests : s2<>abcdef, s2<>ch */
s2 = "abc".concat("def"); /* après tests : s2<>abcdef, s2<>ch */
s2 = s4+"def"; /* après tests : s2<>abcdef, s2<>ch */
s2="abc"+"def"; /* après tests : s2 ==abcdef, s2 == ch */
s2="abcdef"; /* après tests : s2 == abcdef, s2 == ch */
//-- tests d'égalité avec l'opérateur = =
if( s2 == "abcdef" ) System.out.println ("s2==abcdef");
else System.out.println ("s2<>abcdef");
if( s2 == ch ) System.out.println ("s2==ch");
else System.out.println ("s2<>ch");
Nous remarquons que selon que l'on utilise ou non des littéraux les
résultats du test ne sont pas les mêmes.
CONSEIL
Pour éviter des confusions et mémoriser des cas particuliers, il est conseillé d’utiliser la méthode equals pour tester la valeur d'égalité de deux chaînes.
Rapport entre String et char
Une chaîne String contient des éléments de base
de type char comment passe-t-on de l'un à l'autre type.
1°) On ne peut pas considérer un char comme un cas particulier de String, le transtypage suivant est refusé :
char car = 'r';
String s;
s = (String)car;
Il faut utiliser la méthode de conversion valueOf des String :
s = String.valueOf(car);
2°) On peut concaténer avec l'opérateur +, des char à
une chaîne String déjà existante et affecter le résultat
à une String :
String s1 , s2 ="abc" ;
char c = 'e' ;
s1 = s2 + 'd' ;
s1 = s2 + c ;
L'écriture suivante sera refusée :
Ecriture correcte associée :
String s1 , s2 = "abc" ;
char c = 'e' ;
s1 = 'd' + c ; // types incompatibles
s1 = 'd' + 'e'; // types incompatibles
String s1 , s2 = "abc" ;
char c = 'e' ;
s1 = "d" + String.valueOf (c) ;
s1 = "d" + "e";
- Le caractère 'e' est de type char,
- La chaîne "e" est de type String (elle ne contient qu'un seul caractère)
Pour plus d'information sur toutes les méthode de la classe String
voici telle qu'elle est présentée par Sun dans la documentation
du JDK 1.4.2 (http://java.sun.com), la liste des méthodes de cette
classe.
2. Les tableaux Arrays, les matrices
Dès que l'on travaille avec de nombreuses données homogènes
( de même type) la première structure de base permettant le
regroupement de ces données est le tableau. Java comme tous
les langages algorithmiques propose cette structure au programmeur.
Comme pour les String, pour des raisons d'efficacité dans l'encombrement
mémoire, les tableaux sont gérés par Java, comme des
objets.
2.1 Les tableaux à une dimension
Déclaration d'une variable de tableau :
int [] table1;
char [] table2;
float [] table3;
...
String [] tableStr;
Déclaration d'une variable de tableau avec définition
explicite de taille :
int [] table1 =
new int [5];
char [] table2 = new char [12];
float [] table3 = new float [8];
...
String [] tableStr = new String [9];
Le mot clef new correspond à la création d'un nouvel objet (un nouveau tableau) dont la taille est fixée par la valeur indiquée entre les crochets. Ici 4 tableaux sont créés et prêts à être utilisés : table1 contiendra 5 entiers 32 bits, table2 contiendra 12 caractères, table3 contiendra 8 réels en simple précision et tableStr contiendra 9 chaînes de type String.
On peut aussi déclarer un tableau sous la forme de deux instructions : une instruction de déclaration et une instruction de définition de taille avec le mot clef new, la seconde pouvant être mise n'importe où dans le corps d'instruction, mais elle doit être utilisée avant toute manipulation du tableau. Cette dernière instruction de définition peut être répétée plusieurs fois dans le programme, il s'agira alors à chaque fois de la création d'un nouvel objet (donc un nouveau tableau), l'ancien étant détruit et désalloué automatiquement par le ramasse-miettes (garbage collector) de Java.
int [] table1;
char [] table2;
float [] table3;
String [] tableStr;
....
table1 = new int [5];
table2 = new char [12];
table3 = new float [8];
tableStr = new String [9];
Déclaration et initialisation d'un tableau avec définition
implicite de taille :
int [] table1 =
{17,-9,4,3,57};
char [] table2 = {'a','j','k','m','z'};
float [] table3 = {-15.7f,75,-22.03f,3,57};
String [] tableStr = {"chat","chien","souris","rat","vache"};
Dans cette éventualité Java crée le tableau, calcule
sa taille et l'initialise avec les valeurs fournies.
Il existe un attribut général de la classe des tableaux, qui contient la taille d'un tableau quelque soit son type, c'est l'attribut length. Exemple : |
Il existe des classes permettant de manipuler les tableaux :
Un tableau en Java comme dans les autres langages algorithmiques s'utilise
à travers une cellule de ce tableau repérée par un
indice obligatoirement de type entier ou un char considéré
comme un entier (byte, short, int, long ou char).
Le premier élément d'un tableau est numéroté 0, le dernier length-1.
On peut ranger des valeurs ou des expressions du type général du tableau dans une cellule du tableau.
Exemple avec un tableau de type int :
int [] table1 = new int [5]; // dans une instruction d'affectation: table1[0] = -458; table1[4] = 5891; table1[5] = 72; <--- est une erreur de dépassement de la taille ! (valeur entre 0 et 4) // dans une instruction de boucle:
|
Même exemple avec un tableau de type char :
char [] table2 = new char [7]; table2[0] = '?' ; |
Remarque :
Dans une classe exécutable la méthode main reçoit en paramètre un tableau de String nommé args qui correspond en fait aux éventuels paramètres de l'application elle-même: static void main(String [] args) |
Les tableaux en Java peuvent être à deux dimensions auquel cas ils sont appelés des matrices, ce aussi des objets et ils se comportent comme les tableaux à une dimension tant au niveau des déclarations qu'au niveau des utilisations. La déclaration s'effectue avec deux opérateurs crochets [ ] [ ] .
Leur structuration n'est pas semblable à
celle des tableaux pascal, en fait en java une matrice est composée
de plusieurs tableaux unidimensionnels de même taille (pour fixer les
idées nous les appellerons les lignes de la matrice) : dans une déclaration
Java le premier crochet sert à indiquer le nombre de lignes (nombre
de tableaux à une dimension), le second crochet sert à indiquer
la taille de la ligne.
Un tel tableau à deux dimensions, peut être considéré
comme un tableau unidimensionnel de pointeurs, où chaque pointeur
référence un autre tableau unidimensionnel.
Voici une manière imagée de visualiser une matrice à
n+1 lignes et à p+1 colonnes
int [ ][ ] table = new int [n+1][p+1];
Les tableaux multiples en Java sont utilisables comme des tableaux unidimensionnels.
Si l'on garde bien présent à l'esprit le fait qu'une cellule
contient une référence vers un autre tableau, on peut alors
écrire en Java soient des instructions pascal like comme table[i,j]
traduite en java par table[i][j], soient des instructions spécifiques
à java n'ayant pas d'équivalent en pascal comme dans l'exemple
ci-après :
table[0] = new int[p+1];
table[1] = new int[p+1];
Dans chacune de ces deux instructions nous créons un objet de tableau unidimensionnel qui est référencé par la cellule de rang 0, puis par celle de rang 1.
Ou encore, en illustrant ce qui se passe après chaque instruction :
int [ ][ ] table = new int [n+1][p+1];
table[0] = new int[p+1];
int [ ] table1 = new int [p+1];
table[1] = table1 ;
Rien n'oblige les tableaux référencés d'avoir la
même dimension, ce type de tableau se dénomme tableaux en escalier
ou tableaux déchiquetés en Java :
int [ ][ ] table = new int [3][ ];
table[0] = new int[2];
table[1] = new int[4];
table[2] = new int[3];
Si l'on souhaite réellement utiliser des matrices (dans lequel
toutes les lignes ont la même dimension) on emploiera l'écriture
pascal-like, comme dans l'exemple qui suit.
Exemple de matrice de type int :
int [][] table1 = new int [2][3];// deux lignes de dimension 3 chacunes // dans une instruction d'affectation: table1[0][0] = -458; table1[2][5] = -3; <--- est une erreur de dépassement ! (valeur entre 0 et 1) table1[1][4] = 83; <--- est une erreur de dépassement ! (valeur entre 0 et 4) // dans une instruction de boucle:
// dans une instruction de boucles imbriquées:
|
Le même attribut général length de la classe des tableaux, contient la taille du tableau : Exemple : matrice à deux lignes de dimension 3 chacune
Java initialise les tableaux par défaut
à 0 pour les int, byte, ... et à null pour les
objets. |
Un tabeau array à une dimension, lorsque sa taille a été fixée soit par une définition explicite, soit par une définition implicite, ne peut plus changer de taille, c'est donc une structure statique.
char [] TableCar ;
TableCar = new char[8]; //définition de la taille et création
d'un nouvel objet tableau à 8 cellules
TableCar[0] = 'a';
TableCar[1] = '#';
...
TableCar[7] = '?';
Si l'on rajoute l'instruction suivante aux précédentes
<TableCar= new char[10]; > il y a création d'un nouveau
tableau de même nom et de taille 10, l'ancien tableau à 8 cellules
est alors détruit. Nous ne redimensionnons pas le tableau, mais en
fait nous créons un nouvel objet ayant la même reférence
que le précédent :
Ce qui nous donne après exécution de la liste des instructions
ci-dessous, un tableau TabCar ne contenant plus rien :
char [] TableCar ;
TableCar = new char[8];
TableCar[0] = 'a';
TableCar[1] = '#';
...
TableCar[7] = '?';
TableCar= new char[10];
Si l'on veut "agrandir" un tableau pendant l'exécution il faut en déclarer un nouveau plus grand et recopier l'ancien dans le nouveau.
Il est possible d'éviter cette façon de faire en utilisant un vecteur (tableau unidimensionnel dynamique) de la classe Vector, présent dans le package java.util.Vector. Ce sont en fait des listes dynamiques gérées comme des tableaux.
Un objet de classe Vector peut "grandir" automatiquement d'un certain nombre de cellules pendant l'exécution, c'est le programmeur qui peut fixer la valeur d'augmentation du nombre de cellules supplémentaires dès que la capacité maximale en cours est dépassée. Dans le cas où la valeur d'augmentation n'est pas fixée, c'est la machine virtuelle Java qui procède à une augmentation par défaut (doublement dès que le maximum est atteint).
Vous pouvez utiliser le type Vector uniquement dans le cas d'objets et non d'éléments de type élémentaires (byte, short, int, long ou char ne sont pas autorisés), comme par exemple les String ou tout autre objet de Java ou que vous créez vous-même.
Les principales méthodes permettant de manipuler les éléments d'un Vector sont :
void addElement(Object obj) | ajouter un élément à la fin du vecteur |
void clear( ) | effacer tous les éléments du vecteur |
Object elementAt(int index) | élément situé au rang = 'index' |
int indexOf(Object elem) | rang de l'élément 'elem' |
Object remove(int index) | efface l'élément situé au rang = 'index' |
void setElementAt(Object obj, int index) | remplace l'élément de rang 'index' par obj |
int size( ) | nombre d'éléments du vecteur |
Voici un exemple simple de vecteur de chaînes utilisant quelques unes des méthodes précédentes :
static void afficheVector(Vector vect)
//affiche un vecteur de String
{
System.out.println( "Vector taille =
" + vect.size( ) );
for ( int i = 0; i<= vect.size( )-1; i++ )
System.out.println( "Vector[" + i + "]=" +
(String)vect.elementAt( i ) );
}
static void VectorInitialiser( )
// initialisation du vecteur de String
{ Vector table = new Vector( );
String str = "val:";
for ( int i = 0; i<=5; i++ )
table.addElement(str + String.valueOf(
i ) );
afficheVector(table);
}
Voici le résultat de l'exécution de la méthodeVectorInitialiser
:
Vector taille = 6
Vector[0] = val:0
Vector[1] = val:1
Vector[2] = val:2
Vector[3] = val:3
Vector[4] = val:4
Vector[5] = val:5
Rappellons qu'une liste linéaire (ou liste chaînée) est un ensemble ordonné d'éléments de même type (structure de donnée homogène) auxquels on accède séquentiellement. Les opérations minimales effectuées sur une liste chaînée sont l'insertion, la modification et la suppression d'un élément quelconque de la liste.
Les listes peuvent être uni-directionnelles, elles sont alors parcourues séquentiellement dans un seul sens :
ou bien bi-directionnelles dans lesquelles chaque élément
possède deux liens de chaînage, l'un sur l'élément
qui le suit l'autre sur l'élément qui le précède,
le parcours s'effectuant en suivant l'un ou l'autre sens de chaînage
:
La classe LinkedList présente dans le package java.util.LinkedList, est en Java une implémentation de la liste chaînée bi-directionnelle, comme la classe Vector, les éléments de la classe LinkedList ne peuvent être que des objets et non de type élémentaires (byte, short, int, long ou char ne sont pas autorisés),
Quelques méthodes permettant de manipuler les éléments d'une LinkedList :
void addFirst(Object obj) | ajouter un élément au début de la liste |
void addLast(Object obj) | ajouter un élément à la fin de la liste |
void clear( ) | effacer tous les éléments de la liste |
Object get(int index) | élément situé au rang = 'index' |
int indexOf(Object elem) | rang de l'élément 'elem' |
Object remove(int index) | efface l'élément situé au rang = 'index' |
Object set( int index , Object obj) | remplace l'élément de rang 'index' par obj |
int size( ) | nombre d'éléments de la liste |
Reprenons l'exemple précédent sur une liste de type LinkedList d'éléments de type String :
import java.util.LinkedList; class ApplicationLinkedList { static void afficheLinkedList (LinkedList liste ) |
Voici le résultat de l'exécution de la méthode
main de la classe ApplicationLinkedList :
liste taille = 6
liste(0) = val:0
liste(1) = val:1
liste(2) = val:2
liste(3) = val:3
liste(4) = val:4
liste(5) = val:5
Un programme travaille avec ses données internes, mais habituellement
il lui est très souvent nécessaire d'aller chercher en entrée,
on dit lire, des nouvelles données (texte, image, son,...)
en provenance de diverses sources (périphériques, autres applications...).
Réciproquement, un programme peut après traitement, délivrer
en sortie des résultats, on dit écrire,
dans un fichier ou vers une autre application.
En Java, toutes ces données sont échangées en entrée et en sortie à travers des flux (Stream).
Un flux est une sorte de tuyau de transport séquentiel de
données.
Il existe un flux par type de données à transporter
:
Un flux est unidirectionnel : il y a donc des flux d'entrée et des flux de sortie :
Afin de jouer un son stocké dans un fichier, l'application Java ouvre
en entrée, un flux associé aux sons et lit ce flux séquentiellement
afin ensuite de traiter ce son (modifier ou jouer le son).
La même application peut aussi traiter des images à partir
d'un fichier d'images et renvoyer ces images dans le fichier après
traitement. Java ouvre un flux en entrée sur le fichier image et un
flux en sortie sur le même fichier, l'application lit séquentiellement
le flux d'entrée (octet par octet par exemple) et écrit séquentiellement
dans le flux de sortie.
Java met à notre disposition dans le package java.io.*,
deux grandes catégories de flux :
( la notation "*" dans package java.io.* indique que l'on
utilise toutes les classes du package java.io)
|
Etant donné l'utilité de tels flux nous donnons exhaustivement
la liste et la fonction de chaque classe pour chacune des deux familles.
5.2 Les flux d'octets en entrée
Cette sous-famille de flux d'entrée contient 7 classes dérivant toutes de la classe abstraite InputStream.
Fonction des classes de flux d'octets en entrée
Classes utilisées pour la communication | |
FileInputStream | lecture de fichiers octets par octets. |
PipedInputStream | récupère des données provenant d'un flux de sortie (cf. PipedOutputStream). |
ByteArrayInputStream | lit des données dans un tampon structuré sous forme d'un array. |
Classes utilisées pour le traitement | |
SequenceInputStream | concaténation d'une énumération de plusieurs flux d'entrée en un seul flux d'entrée. |
StringBufferInputStream | lecture d'une String (Sun déconseille son utilisation et préconise son remplacement par StringReader). |
ObjectInputStream | lecture d'objets Java. |
FilterInputStream | lit à partir d'un InputStream quelconque des données, en "filtrant" certaines données. |
5.3 Les flux d'octets en sortie
Cette sous-famille de flux de sortie contient 5 classes dérivant toutes de la classe abstraite OutputStream.
Fonction des classes de flux d'octets en sortie
Classes utilisées pour la communication | |
FileOutputStream | écriture de fichiers octets par octets. |
PipedOutputStream | envoie des données vers un flux d'entrée (cf. PipedInputStream). |
ByteArrayOutputStream | écrit des données dans un tampon structuré sous forme d'un array. |
Classes utilisées pour le traitement | |
ObjectOutputStream | écriture d'objets Java lisibles avec ObjectInputStream. |
FilterOutputStream | écrit à partir d'un OutputStream quelconque des données, en "filtrant" certaines données. |
5.4 Les opérations d'entrée sortie standard dans une application
Java met à votre disposition 3 flux spécifiques présents comme attributs dans la classe System du package java.lang.System :
Le flux d'entrée System.in est connecté à
l'entrée standard qui est par défaut le clavier.
Le flux de sortie System.out est connecté à la sortie
standard qui est par défaut l'écran.
Le flux de sortie System.err est connecté à la sortie
standard qui est par défaut l'écran.
La classe PrintStream dérive de la classe FilterOutputStream. Elle ajoute de nouvelles fonctionnalités à un flux de sortie, en particulier le flux out possède ainsi une méthode println redéfinies avec plusieurs signatures ( plusieurs en-têtes différentes : byte, short, char, float,...) qui lui permet d'écrire des entiers de toute taille, des caractères, des réels...
Vous avez pu remarquer que depuis le début nous utilisions pour afficher nos résultats, l'instruction System.out.println(...); qui en fait correspond à l'utilisation de la méthode println de la classe PrintStream.
Exemple d'utilisation simple des flux System.out et System.in :
public static void main(String[] args) throws IOException { System.out.println("Appuyez sur la touche <Entrée> :"); //message écran System.in.read( ); // attend la frappe clavier de la touche <Entrée> } |
Dans Java, le flux System.in appartient à la classe InputStream et donc il est moins bien traité que le flux System.out et donc il n'y a pas en Java quelque chose qui ressemble à l'instruction readln du pascal par exemple. Le manque de souplesse semble provenir du fait qu'une méthode ne peut renvoyer son résultat de type élémentaire que par l'instruction return et il n'est pas possible de redéfinir une méthode uniquement par le type de son résultat.
Afin de pallier à cet inconvénient il vous est fourni une classe Readln avec une méthode de lecture au clavier pour chaque type élémentaire. En mettant le fichier Readln.class dans le même dossier que votre application vous pouvez vous servir de cette classe pour lire au clavier dans vos programmes n'importe quelles variables de type élémentaire.
Méthodes de lecture clavier dans la classe Readln
String unstring( ) | lecture clavier d'un chaîne de type String. |
byte unbyte( ) | lecture clavier d'un entier de type byte. |
short unshort( ) | lecture clavier d'un entier de type short. |
int unint( ) | lecture clavier d'un entier de type int. |
long unlong( ) | lecture clavier d'un entier de type long. |
double undouble( ) | lecture clavier d'un réel de type double. |
float unfloat( ) | lecture clavier d'un réel de type float. |
char unchar( ) | lecture clavier d'un caractère. |
Voici un exemple d'utilisation de ces méthodes dans un programme
:
class ApplicationLireClavier {
public static void main(String [] argument) { |
Le source de la classe Readln est donné ci-dessous à titre indicatif et sans commentaires particulier car il s'agit simplement d'un outil.
import java.io.*;
public class Readln {
public static String unstring( ) // Lire
un String
{
String Strloc = new String(); //<=> Strloc ="";
char Carlu='\0';
try {
while ((Carlu=(char)
System.in.read()) !='\n')
if (Carlu
!= '\r') Strloc = Strloc+Carlu;
}
catch (IOException e) {
System.out.println("Erreur
de saisie");
System.exit(0);
}
return Strloc;
} // fin de unstring()
public static byte unbyte( ) // Lire un entier de type byte
{
byte b=0;
try {
b=Byte.parseByte(unstring());
}
catch (NumberFormatException e) {
System.out.println("Entier
byte incorrect");
System.exit(0);
}
return b ;
} // fin de unbyte()
public static short unshort( ) // Lire un entier short
{
short s=0;
try {
s=Short.parseShort(unstring());
}
catch (NumberFormatException e) {
System.out.println("Entier
short incorrect");
System.exit(0);
}
return s ;
} // fin de unshort()
public static int unint( )
// Lire un entier
{
int i=0;
long loc=unlong();// un int
est un long particulier
i=(int)loc;
return i ;
} // fin de unint()
public static long unlong( ) // Lire un entier long
{
long L=0;
try {
L=Integer.parseInt(unstring());
}
catch (NumberFormatException e) {
System.out.println("Entier
long incorrect");
System.exit(0);
}
return L ;
} // fin de unlong()
public static double undouble( ) // Lire un double
{
double D=0.0; // type réel
par défaut de Java
try {
D=Double.valueOf(unstring()).doubleValue();
}
catch (NumberFormatException e) {
System.out.println("Réel
double incorrect");
System.exit(0);
}
return D ;
} // fin de undouble()
public static float unfloat( ) // Lire un float
{
float F=0.0f; // sinon double
par défaut
try {
F=Double.valueOf(unstring()).floatValue();
}
catch (NumberFormatException e) {
System.out.println("Format
numérique incorrect");
System.exit(0);
}
return F ;
} // fin de unfloat()
public static char unchar( ) // Lire un caractere
{
String Strloc=unstring();// un caractère
est un string particulier
if (Strloc.length() = = 0)
return '\n';
else
return Strloc.charAt(0);// on ne prend que le premier caractère
} // fin de unchar()
}
Cette sous-famille de flux de données sur 16 bits contient des classes dérivant toutes de la classe abstraite Reader pour les flux en entrée, et des classes relativement aux flux en sortie dérivant de la classe abstraite Writer.
Fonction des classes de flux de caractères en entrée
BufferedReader | lecture de caractères dans un tampon. |
CharArrayReader | lit de caractères dans un tampon structuré sous forme d'un array. |
FileReader | lecture de caractères dans un fichier texte. |
FilterReader | lit à partir d'un Reader quelconque des caractères, en "filtrant" certaines caractères. |
InputStreamReader | conversion de flux d'octets en flux de caractères (8 bits en 16 bits) |
LineNumberReader | lecture de caractères dans un tampon (dérive de BufferedReader) avec comptage de lignes. |
PipedReader | récupère des données provenant d'un flux de caractères en sortie (cf. PipedWriter). |
StringReader | lecture de caractères à partir d'une chaîne de type String. |
Fonction des classes de flux de caractères en sortie
BufferedWriter | écriture de caractères dans un tampon. |
CharArrayWriterWriter | écrit des caractères dans un tampon structuré sous forme d'un array. |
FileWriter | écriture de caractères dans un fichier texte. |
FilterWriter | écrit à partir d'un Reader quelconque des caractères, en "filtrant" certaines caractères. |
OutputStreamWriter | conversion de flux d'octets en flux de caractères (8 bits en 16 bits) |
PipedWriter | envoie des données vers un flux d'entrée (cf. PipedReader). |
StringWriter | écriture de caractères dans une chaîne de type String. |
5.6 Lecture et écriture dans un fichier de
texte
Il existe une classe dénommée File (dans java.io.File) qui est une représentation abstraite des fichiers, des répertoires et des chemins d'accès. Cette classe permet de créer un fichier, de l'effacer, de le renommer, de créer des répertoires etc...
Pour construire un fichier (texte ou non) il est nécessaire de le créer, puis d'y écrire des données à l'intérieur. Ces opérations passent obligatoirement en Java, par la connection du fichier après sa création, à un flux de sortie. Pour utiliser un fichier déjà créé (présent sur disque local ou télétransmis) il est nécessaire de se servir d'un flux d'entrée.
Conseil pratique : pour tous vos fichiers utilisez systématiquement les flux d'entrée et de sortie bufférisés (BufferedWriter et BufferedReader par exemple, pour vos fichiers de textes). Dans le cas d'un flux non bufférisé le programme lit ou écrit par exemple sur le disque dur, les données au fur et à mesure, alors que les accès disque sont excessivement coûteux en temps.
Exemple écriture non bufférisée de caractères dans un fichier texte :
Ci-dessous un exemple de méthode permettant de créer un
fichier de caractères et d'écrire une suite de caractères
terminée par le caractère '#', on utilise un flux de la classe
FileWriter non bufférisée :
public static void fichierFileWriter(String nomFichier)
{ try { FileWriter out = new FileWriter(nomFichier); out.write("Ceci est une ligne FileWriter"); out.write('#'); out.close( ); } catch (IOException err) { System.out.println( "Erreur : " + err ); } } |
L'exécution de cette méthode produit le texte suivant
:
Ceci est une ligne FileWriter#
Un flux bufférisé stocke les données dans un tampon (buffer, ou mémoire intermédiaire) en mémoire centrale, puis lorsque le tampon est plein, le flux transfert le paquet de données contenu dans le tampon vers le fichier (en sortie) ou en provenance du fichier en entrée. Dans le cas d'un disque dur, les temps d'accès au disque sont optimisés puisque celui-ci est moins fréquemment sollicité par l'écriture.
Exemple écriture bufférisée de caractères dans un fichier texte :
Ci-dessous un exemple de méthode permettant de créer un
fichier de caractères et d'écrire une suite de caractères
terminée par le caractère # , on utilise un flux de
la classe BufferedWriter bufférisée qui comporte
la même méthode write, mais qui possède en plus la méthode
newLine ajoutant un end of line (fin de ligne) à une suite de caractères,
permettant le stockage simple de texte constitué de lignes:
public static void fichierBufferedWriter(String nomFichier)
{ try { fluxwrite = new FileWriter(nomFichier); BufferedWriter out = new BufferedWriter(fluxwrite); out.write("Ceci est une ligne FileBuffWriter"); out.write('#'); out.write("Ceci est la ligne FileBuffWriter n° 1"); out.newLine( ); //écrit le eoln out.write("Ceci est la ligne FileBuffWriter n° 2"); out.newLine( ); //écrit le eoln out.close( ); } catch (IOException err) { System.out.println( "Erreur : " + err ); } } |
L'exécution de cette méthode produit le texte suivant
:
Ceci est une ligne FileBuffWriter#Ceci est la ligne
FileBuffWriter n° 1
Ceci est la ligne FileBuffWriter n° 2
Nous avons utilisé la déclaration de flux bufférisée explicite complète :
fluxwrite = new FileWriter(nomFichier); BufferedWriter out = new BufferedWriter(fluxwrite); |
Java autorise une déclaration implicite raccourcie équivalente :
BufferedWriter out = new BufferedWriter(newFileWriter(nomFichier)); |