4. Classi di uso comune in Java
In questo capitolo presentiamo una serie di classi Java comunemente utilizzate. Queste dispongono di numerosi attributi, metodi e costruttori. In ogni caso, presentiamo solo una piccola parte delle classi. I dettagli su queste sono disponibili nella guida di Java, che presentiamo ora.
4.1. La documentazione
Se avete installato il JDK di Sun nella cartella <jdk>, la documentazione è disponibile nella cartella <jdk>\docs:

A volte si dispone di un JDK ma non della documentazione. Questa è disponibile sul sito web di Sun all'indirizzo http://www.sun.com. Nella cartella docs troverete un file index.html, che funge da punto di partenza per la guida del JDK:


Il link "API & Language" sopra riportato consente di accedere alle classi Java. Il link "Demos/Tutorials" è particolarmente utile per trovare esempi di programmi Java. Seguiamo il link "API & Language":

Seguiamo il link API della piattaforma Java 2:

Questa pagina è il vero punto di partenza per la documentazione delle classi. È possibile creare un collegamento per accedervi rapidamente. L'URL è <jdk>\docs\api\index.html. Contiene collegamenti a centinaia di classi Java presenti nel JDK. Quando si è alle prime armi, la sfida principale è capire a cosa servono queste diverse classi. Inizialmente, questa risorsa è utile solo se si conosce il nome della classe su cui si desiderano informazioni. Puoi anche usare i nomi delle classi come guida, poiché di solito indicano lo scopo della classe.
Facciamo un esempio e cerchiamo informazioni sulla classe Vector, che implementa un array dinamico. Basta cercare il link alla classe Vector nell'elenco delle classi nel riquadro di sinistra:

e clicca sul link per visualizzare la definizione della classe:

Lì troverai
- la gerarchia in cui si trova la classe, in questo caso java.util.Vector
- l'elenco dei campi (attributi) della classe
- l'elenco dei costruttori
- l'elenco dei metodi
Nelle sezioni seguenti presenteremo diverse classi. Invitiamo il lettore a verificare sistematicamente la definizione completa delle classi utilizzate.
4.2. Classi di test
Gli esempi seguenti utilizzano talvolta le classi Person e Teacher. Ne forniamo qui le definizioni.
public class personne{
// last name, first name, age
private String prenom;
private String nom;
private int age;
// builder 1
public personne(String P, String N, int age){
this.prenom=P;
this.nom=N;
this.age=age;
}
// builder 2
public personne(personne P){
this.prenom=P.prenom;
this.nom=P.nom;
this.age=P.age;
}
// toString
public String toString(){
return "personne("+prenom+","+nom+","+age+")";
}
// accessors
public String getPrenom(){
return prenom;
}
public String getNom(){
return nom;
}
public int getAge(){
return age;
}
//modifiers
public void setPrenom(String P){
this.prenom=P;
}
public void setNom(String N){
this.nom=N;
}
public void setAge(int age){
this.age=age;
}
}
La classe Teacher deriva dalla classe Person ed è definita come segue:
class enseignant extends personne{
// attributes
private int section;
// manufacturer
public enseignant(String P, String N, int age,int section){
super(P,N,age);
this.section=section;
}
// toString
public String toString(){
return "etudiant("+super.toString()+","+section+")";
}
}
Utilizzeremo anche una classe studente derivata dalla classe persona e definita come segue:
class etudiant extends personne{
String numero;
public etudiant(String P, String N, int age,String numero){
super(P,N,age);
this.numero=numero;
}
public String toString(){
return "etudiant("+super.toString()+","+numero+")";
}
}
4.3. La classe String
La classe String rappresenta le stringhe di caratteri. Supponiamo che *name* sia una variabile di tipo stringa:
*String name;*
name è un riferimento a un oggetto che non è stato ancora inizializzato. Può essere inizializzato in due modi:
**name = "horse"** oppure **name = new String("horse")**
Entrambi i metodi sono equivalenti. Se in seguito scriviamo name="fish", name farà riferimento a un nuovo oggetto. Il vecchio oggetto String("horse") andrà perso e la memoria che occupava verrà recuperata.
La classe String ha molti attributi e metodi. Eccone alcuni:
public char charAt(int i) | restituisce il carattere all'indice i nella stringa, dove il primo carattere ha indice 0. Pertanto, `String("horse").charAt(3)` è uguale a 'h' |
public int compareTo(string2) | string1.compareTo(string2) confronta string1 con string2 e restituisce 0 se string1 = string2, 1 se string1 > string2 e -1 se string1 < string2 |
public boolean equals(Object anObject) | string1.equals(string2) restituisce true se string1 = string2, false in caso contrario |
public String toLowerCase() | string1.toLowerCase() converte string1 in minuscolo |
public String toUpperCase() | string1.toUpperCase() converte string1 in maiuscolo |
public String trim() | string1.trim() rimuove gli spazi iniziali e finali da string1 |
public String substring(int beginIndex, int endIndex) | String("chapeau").subString(2,4) restituisce la stringa "ape" |
public char[] toCharArray() | converte i caratteri della stringa in un array di caratteri |
int length() | numero di caratteri nella stringa |
int indexOf(String string2) | restituisce la prima occorrenza di string2 nella stringa corrente, oppure -1 se string2 non è presente |
int indexOf(String string2, int startIndex) | Restituisce la prima occorrenza di string2 nella stringa corrente, oppure -1 se string2 non viene trovata. La ricerca inizia dal carattere alla posizione startIndex. |
int lastIndexOf(String string2) | Restituisce l'ultima posizione di string2 nella stringa corrente, oppure -1 se string2 non è presente |
boolean startsWith(String string2) | restituisce true se la stringa corrente inizia con string2 |
boolean endsWith(String string2) | restituisce true se la stringa corrente termina con string2 |
boolean matches(String regex) | restituisce true se la stringa corrente corrisponde all'espressione regolare regex. |
String[] split(String regex) | La stringa corrente è costituita da campi separati da una stringa di caratteri corrispondente all'espressione regolare regex. Il metodo split recupera i campi in un array. |
String replace(char oldChar, char newChar) | Sostituisce il carattere oldChar con il carattere newChar nella stringa corrente. |
Ecco un programma di esempio:
// imports
import java.io.*;
public class string1{
// a demonstration class
public static void main(String[] args){
String uneChaine="l'oiseau vole au-dessus des nuages";
affiche("uneChaine="+uneChaine);
affiche("uneChaine.Length="+uneChaine.length());
affiche("chaine[10]="+uneChaine.charAt(10));
affiche("uneChaine.IndexOf(\"vole\")="+uneChaine.indexOf("vole"));
affiche("uneChaine.IndexOf(\"x\")="+uneChaine.indexOf("x"));
affiche("uneChaine.LastIndexOf('a')="+uneChaine.lastIndexOf('a'));
affiche("uneChaine.LastIndexOf('x')="+uneChaine.lastIndexOf('x'));
affiche("uneChaine.substring(4,7)="+uneChaine.substring(4,7));
affiche("uneChaine.ToUpper()="+uneChaine.toUpperCase());
affiche("uneChaine.ToLower()="+uneChaine.toLowerCase());
affiche("uneChaine.Replace('a','A')="+uneChaine.replace('a','A'));
String[] champs=uneChaine.split("\\s+");
for (int i=0;i<champs.length;i++){
affiche("champs["+i+"]=["+champs[i]+"]");
}//for
affiche("(\" abc \").trim()=["+" abc ".trim()+"]");
}//Main
// poster
public static void affiche(String msg){
// poster msg
System.out.println(msg);
}//poster
}//class
e i risultati ottenuti:
uneChaine=l'oiseau vole au-dessus des nuages
uneChaine.Length=34
chaine[10]=o
uneChaine.IndexOf("vole")=9
uneChaine.IndexOf("x")=-1
uneChaine.LastIndexOf('a')=30
uneChaine.LastIndexOf('x')=-1
uneChaine.substring(4,7)=sea
uneChaine.ToUpper()=L'OISEAU VOLE AU-DESSUS DES NUAGES
uneChaine.ToLower()=l'oiseau vole au-dessus des nuages
uneChaine.Replace('a','A')=l'oiseAu vole Au-dessus des nuAges
champs[0]=[l'oiseau]
champs[1]=[vole]
champs[2]=[au-dessus]
champs[3]=[des]
champs[4]=[nuages]
(" abc ").trim()=[abc]
4.4. La classe Vector
Un vettore è un array dinamico i cui elementi sono riferimenti a oggetti. Si tratta quindi di un array di oggetti la cui dimensione può variare nel tempo, cosa impossibile con gli array statici che abbiamo visto finora. Ecco alcuni campi, costruttori o metodi di questa classe:
public Vector() | crea un vettore vuoto |
public final int size() | numero di elementi nel vettore |
public final void addElement(Object obj) | aggiunge al vettore l'oggetto a cui fa riferimento obj |
public final Object elementAt(int index) | riferimento all'oggetto all'indice nell'array - gli indici partono da 0 |
public final Enumeration elements() | l'insieme degli elementi nell'array come enumerazione |
public final Object firstElement() | riferimento al primo elemento dell'array |
public final Object lastElement() | riferimento all'ultimo elemento del vettore |
public final boolean isEmpty() | restituisce true se l'array è vuoto |
public final void removeElementAt(int index) | rimuove l'elemento all'indice |
public final void removeAllElements() | cancella tutti gli elementi dall'array |
public final String toString() | restituisce una stringa che rappresenta l'array |
Ecco un programma di prova:
// imported classes
import java.util.*;
public class test1{
// main program - static - class method
public static void main(String arg[]){
// creation of objects that are instances of classes
personne p=new personne("Jean","Dupont",30);
enseignant en=new enseignant("Paula","Hanson",56,27);
etudiant et=new etudiant("Chris","Garot",22,"19980405");
System.out.println("p="+p.toString());
System.out.println("en="+en.toString());
System.out.println("et="+et.toString());
// polymorphism
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// a vector
Vector V=new Vector();
V.addElement(p);V.addElement(en);V.addElement(et);
System.out.println("Taille du vecteur V = "+V.size());
for(int i=0;i<V.size();i++){
p2=(personne) V.elementAt(i);
System.out.println("V["+i+"]="+p2.toString());
}
} // fine hand
}// end of class
Compiliamo questo programma:
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>dir
10/06/2002 10:41 1 134 personne.class
10/06/2002 10:41 619 enseignant.class
10/06/2002 10:41 610 etudiant.class
10/06/2002 10:42 1 035 test1.java
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>javac test1.java
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>dir
10/06/2002 10:41 1 134 personne.class
10/06/2002 10:41 619 enseignant.class
10/06/2002 10:41 610 etudiant.class
10/06/2002 10:42 1 035 test1.java
10/06/2002 10:43 1 506 test1.class
Eseguiamo il file test1.class:
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>java test1
p=personne(Jean,Dupont,30)
en=etudiant(personne(Paula,Hanson,56),27)
et=etudiant(personne(Chris,Garot,22),19980405)
p2=etudiant(personne(Paula,Hanson,56),27)
p3=etudiant(personne(Chris,Garot,22),19980405)
Taille du vecteur V = 3
V[0]=personne(Jean,Dupont,30)
V[1]=etudiant(personne(Paula,Hanson,56),27)
V[2]=etudiant(personne(Chris,Garot,22),19980405)
D'ora in poi, non ripeteremo più il processo di compilazione ed esecuzione dei programmi di test. Basta ripetere ciò che è stato fatto sopra.
4.5. La classe ArrayList
La classe ArrayList è analoga alla classe Vector. Si differenzia da quest'ultima principalmente solo quando viene utilizzata contemporaneamente da più thread. I metodi di sincronizzazione dei thread per l'accesso a un Vector o a un ArrayList sono diversi. Al di fuori di questo caso, entrambe le classi possono essere utilizzate in modo intercambiabile. Di seguito sono riportati alcuni campi, costruttori o metodi di questa classe:
ArrayList() | crea un array vuoto |
int size() | numero di elementi nell'array |
void add(Object obj) | aggiunge all'array l'oggetto a cui fa riferimento obj |
void add(int index, Object obj) | aggiunge l'oggetto a cui fa riferimento obj all'array nella posizione index |
Object get(int index) | riferimento all'oggetto all'indice nell'array — gli indici partono da 0 |
boolean isEmpty() | restituisce true se l'array è vuoto |
void remove(int index) | rimuove l'elemento all'indice |
void clear() | cancella tutti gli elementi dall'array |
Object[] toArray() | converte l'array dinamico in un array standard |
String toString() | restituisce una stringa che rappresenta l'array |
Ecco un programma di prova:
// imported classes
import java.util.*;
public class test1{
// main program - static - class method
public static void main(String arg[]){
// creation of objects that are instances of classes
personne p=new personne("Jean","Dupont",30);
enseignant en=new enseignant("Paula","Hanson",56,27);
etudiant et=new etudiant("Chris","Garot",22,"19980405");
System.out.println("p="+p);
System.out.println("en="+en);
System.out.println("et="+et);
// polymorphism
personne p2=(personne)en;
System.out.println("p2="+p2);
personne p3=(personne)et;
System.out.println("p3="+p3);
// a vector
ArrayList personnes=new ArrayList();
personnes.add(p);personnes.add(en);personnes.add(et);
System.out.println("Nombre de personnes = "+personnes.size());
for(int i=0;i<personnes.size();i++){
p2=(personne) personnes.get(i);
System.out.println("personnes["+i+"]="+p2);
}
} // fine hand
}// end of class
I risultati ottenuti sono gli stessi di prima.
4.6. La classe Arrays
La classe java.util.Arrays offre l'accesso a metodi statici che consentono di eseguire diverse operazioni sugli array, in particolare l'ordinamento e la ricerca di elementi. Ecco alcuni di questi metodi:
static void sort(array) | ordina l'array utilizzando l'ordine implicito del tipo di dati dell'array, che si tratti di numeri o stringhe. |
static void sort(Object[] array, Comparator C) | Ordina l'array utilizzando la funzione di confronto C per confrontare gli elementi |
static int binarySearch(array, element) | Restituisce la posizione dell'elemento nell'array, oppure un valore <0 in caso contrario. L'array deve essere stato ordinato in precedenza. |
static int binarySearch(Object[] array, Object element, Comparator C) | Come sopra, ma utilizza la funzione di confronto C per confrontare due elementi nell'array. |
Ecco un primo esempio:
import java.util.*;
public class sort2 implements Comparator{
// an internal private class
private class personne{
private String nom;
private int age;
public personne(String nom, int age){
this.nom=nom; // person's name
this.age=age; // his age
}
// recover age
public int getAge(){
return age;
}
// identity of the person
public String toString(){
return ("["+nom+","+age+"]");
}
}; // class person
// manufacturer
public sort2() {
// a table of people
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// sorting the people table
Arrays.sort(amis,this);
// check
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//manufacturer
// the function that compares people
public int compare(Object o1, Object o2){
// must make
// -1 if o1 "smaller than" o2
// 0 if o1 "equal to" o2
// +1 if o1 "greater than" o2
personne p1=(personne)o1;
personne p2=(personne)o2;
int age1=p1.getAge();
int age2=p2.getAge();
if(age1<age2) return (-1);
else if (age1==age2) return (0);
else return +1;
}//compare
// test function
public static void main(String[] arg){
new sort2();
}//hand
}//class
Esaminiamo questo programma. La funzione main crea un oggetto sort2. Il costruttore della classe sort2 è il seguente:
// manufacturer
public sort2() {
// a table of people
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// sorting the people table
Arrays.sort(amis,this);
// check
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//manufacturer
L'array da ordinare è un array di oggetti Person. La classe Person è definita come privata all'interno della classe sort2. Il metodo statico sort della classe Arrays non sa come ordinare un array di oggetti Person, quindi siamo costretti qui a utilizzare la forma void sort(Object[] obj, Comparator C). Comparator è un'interfaccia che definisce un solo metodo:
e che deve restituire 0 se o1=o2, -1 se o1 < o2, +1 se o1 > o2. Nel prototipo void sort(Object[] obj, Comparator C), il secondo argomento C deve essere un oggetto che implementa l'interfaccia Comparator. Nel costruttore di sort2, abbiamo scelto l'oggetto corrente this:
Questo ci impone di fare due cose:
- indicare che la classe sort2 implementa l'interfaccia Comparator
- scrivere la funzione di confronto nella classe sort2.
Ecco come:
// the function that compares people
public int compare(Object o1, Object o2){
// must make
// -1 if o1 "smaller than" o2
// 0 if o1 "equal to" o2
// +1 if o1 "greater than" o2
personne p1=(personne)o1;
personne p2=(personne)o2;
int age1=p1.getAge();
int age2=p2.getAge();
if(age1<age2) return (-1);
else if (age1==age2) return (0);
else return +1;
}//compare
Per confrontare due oggetti Person, qui usiamo l'età (avremmo potuto usare il nome).
I risultati dell'esecuzione sono i seguenti:
Avremmo potuto adottare un approccio diverso per l'implementazione dell'interfaccia Comparator:
import java.util.*;
public class sort2 {
// an internal private class
private class personne{
…….
}; // class person
// manufacturer
public sort2() {
// a table of people
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// sorting the people table
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compare
}//class
);
// check
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//manufacturer
// the function that compares people
public int compare1(Object o1, Object o2){
// must make
// -1 if o1 "smaller than" o2
// 0 if o1 "equal to" o2
// +1 if o1 "greater than" o2
personne p1=(personne)o1;
personne p2=(personne)o2;
int age1=p1.getAge();
int age2=p2.getAge();
if(age1<age2) return (-1);
else if (age1==age2) return (0);
else return +1;
}//compare1
// hand
public static void main(String[] arg){
new sort2();
}//hand
}//class
L'istruzione di ordinamento è diventata la seguente:
// sorting the people table
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compare
}//class
);
Il secondo parametro del metodo compare deve essere un oggetto che implementi l'interfaccia Comparator. In questo caso, creiamo un oggetto di questo tipo utilizzando new java.util.Comparator(), e il testo che segue {…} definisce la classe da cui viene creato l'oggetto. Si tratta di una classe anonima, poiché non ha un nome. In questa classe anonima, che deve implementare l'interfaccia Comparator, definiamo il metodo compare di tale interfaccia. Questo metodo chiama semplicemente il metodo compare1 della classe sort2. Ci ritroviamo quindi al caso precedente.
La classe sort2 non implementa più l'interfaccia Comparator. Pertanto, la sua dichiarazione diventa:
Ora testiamo il metodo binarySearch della classe Arrays utilizzando il seguente esempio:
import java.util.*;
public class sort4 {
// an internal private class
private class personne{
// attributes
private String nom;
private int age;
// manufacturer
public personne(String nom, int age){
this.nom=nom; // person's name
this.age=age; // his age
}
// retrieve name
public String getNom(){
return nom;
}
// recover age
public int getAge(){
return age;
}
// identity of the person
public String toString(){
return ("["+nom+","+age+"]");
}
}; // class person
// manufacturer
public sort4() {
// a table of people
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// comparators
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compare
}//class
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//compare
}//class
;
// sorting the people table
Arrays.sort(amis,comparateur1);
// check
for(int i=0;i<3;i++)
System.out.println(amis[i]);
// research
cherche("milou",amis,comparateur2);
cherche("xx",amis,comparateur2);
}//manufacturer
// the function that compares people
public int compare1(Object o1, Object o2){
// must make
// -1 if o1 "smaller than" o2
// 0 if o1 "equal to" o2
// +1 if o1 "greater than" o2
personne p1=(personne)o1;
personne p2=(personne)o2;
int age1=p1.getAge();
int age2=p2.getAge();
if(age1<age2) return (-1);
else if (age1==age2) return (0);
else return +1;
}//compare1
// the function that compares a person to a name
public int compare2(Object o1, Object o2){
// o1 is a person
// o2 is a String, the name name2 of a person
// must make
// -1 if o1.nom "smaller than" name2
// 0 if o1.nom "equal to" name2
// +1 if o1.nom "greater than" name2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//compare2
public void cherche(String ami,personne[] amis, Comparator comparateur){
// search for a friend in the friends table
int position=Arrays.binarySearch(amis,ami,comparateur);
// found?
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//search
// hand
public static void main(String[] arg){
new sort4();
}//hand
}//class
Qui abbiamo proceduto in modo leggermente diverso rispetto agli esempi precedenti. I due oggetti Comparator richiesti dai metodi sort e binarySearch sono stati creati e assegnati alle variabili comparator1 e comparator2.
// comparators
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compare
}//class
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//compare
}//class
;
Nel costruttore sort4 viene eseguita due volte una ricerca binaria sull'array friends:
Il metodo search riceve tutti i parametri necessari per chiamare il metodo binarySearch:
public void cherche(String ami,personne[] amis, Comparator comparateur){
// search for a friend in the friends table
int position=Arrays.binarySearch(amis,ami,comparateur);
// found?
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//search
Il metodo binarySearch funziona con il comparatore comparator2, che a sua volta chiama il metodo compare2 della classe sort4. Il metodo restituisce la posizione del nome cercato nell'array se esiste, oppure un numero <0 in caso contrario. Il metodo compare2 viene utilizzato per confrontare un oggetto Person con un nome di tipo String.
// the function that compares a person to a name
public int compare2(Object o1, Object o2){
// o1 is a person
// o2 is a String, the name name2 of a person
// must make
// -1 if o1.nom "smaller than" name2
// 0 if o1.nom "equal to" name2
// +1 if o1.nom "greater than" name2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//compare2
A differenza del metodo sort, il metodo binarySearch non accetta due oggetti Person, bensì un oggetto Person e un oggetto String in quest'ordine. Il primo parametro è un elemento dell'array friends, mentre il secondo è il nome della persona che si sta cercando.
4.7. La classe Enumeration
Enumeration è un'interfaccia, non una classe. Dispone dei seguenti metodi:
public abstract boolean hasMoreElements() | restituisce true se l'enumerazione contiene ancora elementi |
public abstract Object nextElement() | restituisce un riferimento all'elemento successivo nell'enumerazione |
Come si usa un'enumerazione? Generalmente in questo modo:
Enumeration e=… // an enumeration object is retrieved
while(e.hasMoreElements()){
// use e.nextElement() element
}
Ecco un esempio:
// imported classes
import java.util.*;
public class test1{
// main program - static - class method
public static void main(String arg[]){
// creation of objects that are instances of classes
personne p=new personne("Jean","Dupont",30);
enseignant en=new enseignant("Paula","Hanson",56,27);
etudiant et=new etudiant("Chris","Garot",22,"19980405");
System.out.println("p="+p.toString());
System.out.println("en="+en.toString());
System.out.println("et="+et.toString());
// polymorphism
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// a vector
Vector V=new Vector();
V.addElement(p);V.addElement(en);V.addElement(et);
System.out.println("Taille du vecteur V = "+V.size());
int i;
for(i=0;i<V.size();i++){
p2=(personne) V.elementAt(i);
System.out.println("V["+i+"]="+p2.toString());
}
// an enumeration
Enumeration E=V.elements();
i=0;
while(E.hasMoreElements()){
p2=(personne) E.nextElement();
System.out.println("V["+i+"]="+p2.toString());
i++;
}
}// fine hand
}//end of class
Si ottengono i seguenti risultati:
p=personne(Jean,Dupont,30)
en=enseignant(personne(Paula,Hanson,56),27)
et=etudiant(personne(Chris,Garot,22),19980405)
p2=enseignant(personne(Paula,Hanson,56),27)
p3=etudiant(personne(Chris,Garot,22),19980405)
Taille du vecteur V = 3
V[0]=personne(Jean,Dupont,30)
V[1]=enseignant(personne(Paula,Hanson,56),27)
V[2]=etudiant(personne(Chris,Garot,22),19980405)
V[0]=personne(Jean,Dupont,30)
V[1]=enseignant(personne(Paula,Hanson,56),27)
V[2]=etudiant(personne(Chris,Garot,22),19980405)
4.8. La classe HashTable
La classe HashTable consente di implementare un dizionario. Un dizionario può essere visto come un array a due colonne:
chiave | valore |
chiave1 | valore1 |
chiave2 | valore2 |
.. | ... |
Le chiavi sono univoche, ovvero non possono esserci due chiavi identiche. I principali metodi e proprietà della classe Hashtable sono i seguenti:
public Hashtable() | costruttore - crea un dizionario vuoto |
public int size() | numero di elementi nel dizionario, dove un elemento è una coppia (chiave, valore) |
public Object put(Object chiave, Object valore) | aggiunge la coppia (chiave, valore) al dizionario |
public Object get(Object key) | recupera l'oggetto associato alla chiave key oppure restituisce null se la chiave key non esiste |
public boolean containsKey(Object key) | true se la chiave esiste nel dizionario |
public boolean contains(Object value) | true se il valore value esiste nel dizionario |
public Enumeration keys() | restituisce le chiavi del dizionario come enumerazione |
public Object remove(Object key) | rimuove la coppia (chiave, valore) dove chiave=chiave |
public String toString() | identifica il dizionario |
Ecco un esempio:
// imported classes
import java.util.*;
public class test1{
// main program - static - class method
public static void main(String arg[]){
// creation of objects that are instances of classes
personne p=new personne("Jean","Dupont",30);
enseignant en=new enseignant("Paula","Hanson",56,27);
etudiant et=new etudiant("Chris","Garot",22,"19980405");
System.out.println("p="+p.toString());
System.out.println("en="+en.toString());
System.out.println("et="+et.toString());
// polymorphism
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// a dictionary
Hashtable H=new Hashtable();
H.put("personne1",p);
H.put("personne2",en);
H.put("personne3",et);
Enumeration E=H.keys();
int i=0;
String cle;
while(E.hasMoreElements()){
cle=(String) E.nextElement();
p2=(personne) H.get(cle);
System.out.println("clé "+i+"="+cle+" valeur="+p2.toString());
i++;
}
}//fine hand
}//end of class
I risultati sono i seguenti:
p=personne(Jean,Dupont,30)
en=enseignant(personne(Paula,Hanson,56),27)
et=etudiant(personne(Chris,Garot,22),19980405)
p2=enseignant(personne(Paula,Hanson,56),27)
p3=etudiant(personne(Chris,Garot,22),19980405)
clé 0=personne3 valeur=etudiant(personne(Chris,Garot,22),19980405)
clé 1=personne2 valeur=enseignant(personne(Paula,Hanson,56),27)
clé 2=personne1 valeur=personne(Jean,Dupont,30)
4.9. File di testo
4.9.1. Scrittura
Per scrivere su un file, è necessario un flusso di scrittura. A questo scopo è possibile utilizzare la classe FileWriter. I seguenti costruttori sono comunemente utilizzati:
FileWriter(String fileName) | crea un file denominato fileName — è quindi possibile scriverci — qualsiasi file esistente con lo stesso nome viene sovrascritto |
FileWriter(String fileName, boolean append) | come sopra: qualsiasi file esistente con lo stesso nome può essere utilizzato aprendolo in modalità di aggiunta (append=true) |
La classe FileWriter fornisce una serie di metodi per la scrittura su un file, metodi ereditati dalla classe Writer. Per scrivere su un file di testo, è preferibile utilizzare la classe PrintWriter, i cui costruttori comunemente utilizzati sono i seguenti:
PrintWriter(Writer out) | l'argomento è di tipo Writer, ovvero un flusso di scrittura (su un file, in rete, ecc.) |
PrintWriter(Writer out, boolean autoflush) | Come sopra. Il secondo argomento controlla il buffering delle righe. Se impostato su false (impostazione predefinita), le righe scritte nel file passano attraverso un buffer in memoria. Quando il buffer è pieno, viene scritto nel file. Ciò migliora l'accesso al disco. Detto questo, questo comportamento a volte è indesiderabile, in particolare quando si scrive su una rete. |
I metodi utili della classe PrintWriter sono i seguenti:
void print(Type T) | scrive i dati T (String, int, ….) |
void println(Type T) | come sopra, terminando con un carattere di nuova riga |
void flush() | svuota il buffer se non si è in modalità autoflush |
void close() | chiude il flusso di scrittura |
Ecco un programma che scrive alcune righe in un file di testo:
// imports
import java.io.*;
public class ecrire{
public static void main(String[] arg){
// open file
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// write to file
try{
fic.println("Jean,Dupont,27");
fic.println("Pauline,Garcia,24");
fic.println("Gilles,Dumond,56");
} catch (Exception e){
Erreur(e,3);
}
// close file
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// fine hand
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Error
}//class
Il file di output generato dal programma è il seguente:
4.9.2. Lettura
Per leggere il contenuto di un file, è necessario un flusso di lettura associato al file. A tal fine è possibile utilizzare la classe FileReader e il seguente costruttore:
FileReader(String filename) | apre un flusso di lettura dal file specificato. Genera un'eccezione se l'operazione non va a buon fine. |
La classe FileReader dispone di una serie di metodi per la lettura da un file, metodi ereditati dalla classe Reader. Per leggere righe di testo da un file di testo, è preferibile utilizzare la classe BufferedReader con il seguente costruttore:
BufferedReader(Reader in) | apre un flusso di lettura bufferizzato da un flusso di input in. Questo flusso di tipo Reader può provenire dalla tastiera, da un file, dalla rete, ecc. |
I metodi utili della classe BufferedReader sono i seguenti:
int read() | legge un carattere |
String readLine() | legge una riga di testo |
int read(char[] buffer, int offset, int size) | Legge un numero di caratteri specificato dal file e li inserisce nell'array buffer a partire dalla posizione offset. |
void close() | chiude il flusso di lettura |
Ecco un programma che legge il contenuto del file creato in precedenza:
// imported classes
import java.util.*;
import java.io.*;
public class lire{
public static void main(String[] arg){
personne p=null;
// open file
BufferedReader IN=null;
try{
IN=new BufferedReader(new FileReader("out"));
} catch (Exception e){
Erreur(e,1);
}
// data
String ligne=null;
String[] champs=null;
String prenom=null;
String nom=null;
int age=0;
// error handling
try{
while((ligne=IN.readLine())!=null){
champs=ligne.split(",");
prenom=champs[0];
nom=champs[1];
age=Integer.parseInt(champs[2]);
System.out.println(""+new personne(prenom,nom,age));
}// end while
} catch (Exception e){
Erreur(e,2);
}
// close file
try{
IN.close();
} catch (Exception e){
Erreur(e,3);
}
}// fine hand
// Error
public static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}
}// end of class
L'esecuzione del programma produce i seguenti risultati:
4.9.3. Salvataggio di un oggetto persona
Applichiamo quanto appena visto per dotare la classe Person di un metodo che ci consenta di salvare gli attributi di una persona su un file. Aggiungiamo il metodo saveAttributes alla definizione della classe Person:
// ------------------------------
// sauvegarde dans fichier texte
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
Prima di definire la classe Person, non dimenticare di importare il pacchetto java.io:
Il metodo saveAttributes accetta un unico parametro: lo stream PrintWriter su cui deve scrivere. Un programma di prova potrebbe essere simile al seguente:
// imports
import java.io.*;
// import nobody;
public class sauver{
public static void main(String[] arg){
// open file
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// write to file
try{
new personne("Jean","Dupont",27).sauveAttributs(fic);
new personne("Pauline","Garcia",24).sauveAttributs(fic);
new personne("Gilles","Dumond",56).sauveAttributs(fic);
} catch (Exception e){
Erreur(e,3);
}
// close file
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// fine hand
// Error
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Error
}//class
Compiliamo ed eseguiamo questo programma:
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>javac sauver.java
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>dir
10/06/2002 10:52 1 352 personne.class
10/06/2002 10:53 842 sauver.java
10/06/2002 10:53 1 258 sauver.class
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>java sauver
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>dir
10/06/2002 10:52 1 352 personne.class
10/06/2002 10:53 842 sauver.java
10/06/2002 10:53 1 258 sauver.class
10/06/2002 10:53 83 out
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>more out
personne(Jean,Dupont,27)
personne(Pauline,Garcia,24)
personne(Gilles,Dumond,56)
4.10. File binari
4.10.1. La classe RandomAccessFile
La classe RandomAccessFile consente di gestire i file binari, in particolare quelli con una struttura fissa come quelli in C/C++. Ecco alcuni metodi e costruttori utili:
RandomAccessFile(String filename, String mode) | costruttore - apre il file specificato nella modalità specificata. La modalità può essere una delle seguenti: r: apertura in lettura rw: apri per lettura e scrittura |
void writeTTT(TTT value) | scrive il valore nel file. TTT rappresenta il tipo di valore. La rappresentazione in memoria del valore viene scritta così com'è nel file. Esistono quindi writeBoolean, writeByte, writeInt, writeDouble, writeLong, writeFloat, ecc. Per scrivere una stringa, utilizzare writeBytes(String string). |
TTT readTTT() | Legge e restituisce un valore di tipo TTT. Esempi includono readBoolean, readByte, readInt, readDouble, readLong, readFloat, ecc. Il metodo read() legge un byte. |
long length() | dimensione del file in byte |
long getFilePointer() | posizione corrente del puntatore del file |
void seek(long pos) | imposta il cursore del file sul byte pos |
4.10.2. La classe Article
Tutti gli esempi seguenti utilizzeranno la seguente classe Article:
// article structure
private static class article{
// we define the structure
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//item class
La classe Item Java sopra riportata è equivalente alla seguente struttura C
struct article{
char code[4];
char nom[20];
double prix;
int stockActuel;
int stockMinimum;
}//structure
In questo modo, limiteremo il codice a 4 caratteri e il nome a 20.
4.10.3. Crea un record
Il seguente programma scrive un record in un file denominato "data":
// imported classes
import java.io.*;
public class test1{
// tests the writing of a structure (in the C sense) to a binary file
// article structure
private static class article{
// we define the structure
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//item class
public static void main(String arg[]){
// we define the binary file in which the items will be stored
RandomAccessFile fic=null;
// we define an article
article art=new article();
art.code="a100";
art.nom="velo";
art.prix=1000.80;
art.stockActuel=100;
art.stockMinimum=10;
// we define the file
try{
fic=new RandomAccessFile("data","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// we write
try{
ecrire(fic,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement",2);
}//try-catch
// it's over
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}//hand
// writing method
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// code
fic.writeBytes(art.code);
// name limited to 20 characters
art.nom=art.nom.trim();
int l=art.nom.length();
int nbBlancs=20-l;
if(nbBlancs>0){
String blancs="";
for(int i=0;i<nbBlancs;i++) blancs+=" ";
art.nom+=blancs;
} else art.nom=art.nom.substring(0,20);
fic.writeBytes(art.nom);
// the price
fic.writeDouble(art.prix);
// inventories
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// end write
// ------------------------erreur
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// end error
}// fin class
Il seguente programma ci permette di verificare che l'esecuzione sia andata a buon fine.
4.10.4. Leggi un record
// imported classes
import java.io.*;
public class test2{
// tests the writing of a structure (in the C sense) to a binary file
// article structure
private static class article{
// we define the structure
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//item class
public static void main(String arg[]){
// we define the binary file in which the items will be stored
RandomAccessFile fic=null;
// open the file in read mode
try{
fic=new RandomAccessFile("data","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// we read the single article in the file
article art=new article();
try{
lire(fic,art);
} catch (IOException E){
erreur("Erreur lors de la lecture de l'enregistrement",2);
}//try-catch
// the record played back is displayed
affiche(art);
// it's over
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}// fine hand
// reading method
public static void lire(RandomAccessFile fic, article art) throws IOException{
// code reading
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// name
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// price
art.prix=fic.readDouble();
// stocks
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// end write
// ---------------------affiche
public static void affiche(article art){
System.out.println("code : "+art.code);
System.out.println("nom : "+art.nom);
System.out.println("prix : "+art.prix);
System.out.println("Stock actuel : "+art.stockActuel);
System.out.println("Stock minimum : "+art.stockMinimum);
}// end poster
// ------------------------erreur
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// end error
}// end class
I risultati dell'esecuzione sono i seguenti:
E:\data\serge\JAVA\random>java test2
code : a100
nom : velo
prix : 1000.8
Stock actuel : 100
Stock minimum : 10
Abbiamo recuperato con successo il record scritto dal programma di scrittura.
4.10.5. Conversione da testo a binario
Il programma seguente è un'estensione del programma di scrittura dei record. Ora scriviamo più record in un file binario denominato data.bin. I dati sono tratti dal seguente file data.txt:
E:\data\serge\JAVA\random>more data.txt
a100:velo:1000:100:10
b100:pompe:65:6:2
c100:arc:867:10:5
d100:fleches - lot de 6:450:12:8
e100:jouet:10:2:3
// imported classes
import java.io.*;
import java.util.*;
public class test3{
// text file --> binary file
// article structure
private static class article{
// we define the structure
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//item class
public static void main(String arg[]){
// we define the binary file in which the items will be stored
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin",1);
}
// data are taken from a text file
BufferedReader dataTxt=null;
try{
dataTxt=new BufferedReader(new FileReader("data.txt"));
} catch (IOException E){
erreur("Impossible d'ouvrir le fichier data.txt",2);
}
// .txt file --> .bin file
String ligne=null;
String[] champs=null;
int numLigne=0;
String champ=null;
article art=new article(); // item to be created
try{
while((ligne=dataTxt.readLine())!=null){
// a + line
numLigne++;
// decomposition into fields
champs=ligne.split(":");
// 5 fields are required
if(champs.length!=5)
erreur("Ligne "+numLigne+" erronée dans data.txt",3);
//code
art.code=champs[0];
if(art.code.length()!=4)
erreur("Code erroné en ligne "+numLigne+" du fichier data.txt",12);
// last name, first name
art.nom=champs[1];
// price
try{
art.prix=Double.parseDouble(champs[2]);
} catch (Exception E){
erreur("Prix erroné en ligne "+numLigne+" du fichier data.txt",4);
}
// current stock
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// current stock
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// we write the recording
try{
ecrire(dataBin,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement "+numLigne,7);
}
// move on to the next line
}// end while
} catch (IOException E){
erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
}
// it's over
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",10);
}
try{
dataTxt.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.txt",11);
}
}// fine hand
// writing method
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// code
fic.writeBytes(art.code);
// name limited to 20 characters
art.nom=art.nom.trim();
int l=art.nom.length();
int nbBlancs=20-l;
if(nbBlancs>0){
String blancs="";
for(int i=0;i<nbBlancs;i++) blancs+=" ";
art.nom+=blancs;
} else art.nom=art.nom.substring(0,20);
fic.writeBytes(art.nom);
// the price
fic.writeDouble(art.prix);
// inventories
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// end write
// ------------------------erreur
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// end error
}// end class
Il seguente programma consente di verificare che questo abbia funzionato correttamente.
4.10.6. Conversione da binario a testo
Il programma seguente legge il contenuto del file binario data.bin creato in precedenza e ne scrive il contenuto nel file di testo data.text. Se tutto va bene, il file data.text dovrebbe essere identico al file originale data.txt.
// imported classes
import java.io.*;
import java.util.*;
public class test5{
// text file --> binary file
// article structure
private static class article{
// we define the structure
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//item class
// hand
public static void main(String arg[]){
// we define the binary file in which the items will be stored
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// data is written to a text file
PrintWriter dataTxt=null;
try{
dataTxt=new PrintWriter(new FileWriter("data.text"));
} catch (IOException E){
erreur("Impossible d'ouvrir le fichier data.text en écriture",2);
}
// .bin file --> .text file
article art=new article(); // item to be created
// we process the binary file
int numRecord=0;
long l=0; // file size
try{
l=dataBin.length();
} catch (IOException e){
erreur("Erreur lors du calcul de la longueur du fichier data.bin",2);
}
long pos=0; // current position in file
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
// as long as you haven't passed the end of the file
while(pos<l){
// read and use current recordings
numRecord++;
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
affiche(art);
// write the corresponding text line in dataTxt
dataTxt.println(art.code.trim()+":"+art.nom.trim()+":"+art.prix+":"+art.stockActuel+":"+art.stockMinimum);
// shall we continue?
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
}// end while
// it's over
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",2);
}
try{
dataTxt.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.text",2);
}
}// fine hand
// reading method
public static void lire(RandomAccessFile fic, article art) throws IOException{
// code reading
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// name
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// price
art.prix=fic.readDouble();
// stocks
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// end write
// ---------------------affiche
public static void affiche(article art){
System.out.println("code : "+art.code);
System.out.println("nom : "+art.nom);
System.out.println("prix : "+art.prix);
System.out.println("Stock actuel : "+art.stockActuel);
System.out.println("Stock minimum : "+art.stockMinimum);
}// end poster
// ------------------------erreur
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// end error
}// fin class
Ecco un esempio di esecuzione:
E:\data\serge\JAVA\random>java test5
code : a100
nom : velo
prix : 1000.0
Stock actuel : 100
Stock minimum : 0
code : b100
nom : pompe
prix : 65.0
Stock actuel : 6
Stock minimum : 0
code : c100
nom : arc
prix : 867.0
Stock actuel : 10
Stock minimum : 0
code : d100
nom : fleches - lot de 6
prix : 450.0
Stock actuel : 12
Stock minimum : 0
code : e100
nom : jouet
prix : 10.0
Stock actuel : 2
Stock minimum : 0
E:\data\serge\JAVA\random>more data.text
a100:velo:1000.0:100:0
b100:pompe:65.0:6:0
c100:arc:867.0:10:0
d100:fleches - lot de 6:450.0:12:0
e100:jouet:10.0:2:0
4.10.7. Accesso diretto ai record
Quest'ultimo programma dimostra la possibilità di accedere direttamente ai record in un file binario. Visualizza il record del file data.bin il cui numero viene passato come parametro, dove il primo record ha il numero 1.
// imported classes
import java.io.*;
import java.util.*;
public class test6{
// text file --> binary file
// article structure
private static class article{
// we define the structure
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//item class
// hand
public static void main(String[] args){
// check the arguments
int nbArguments=args.length;
String syntaxe="syntaxe : pg numéro_de_fiche";
if(nbArguments!=1)
erreur(syntaxe,20);
// check plug no
int numRecord=0;
try{
numRecord=Integer.parseInt(args[0]);
} catch(Exception e){
erreur(syntaxe+"\nNuméro de fiche incorrect",21);
}
// open the binary file for reading
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// position yourself on the desired card
try{
dataBin.seek((numRecord-1)*40);
} catch (Exception e){
erreur("La fiche "+numRecord+" n'existe pas",23);
}
// we read it
article art=new article();
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
// we display it
affiche(art);
// it's over
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",2);
}//try-catch
}// fine hand
// reading method
public static void lire(RandomAccessFile fic, article art) throws IOException{
// code reading
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// name
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// price
art.prix=fic.readDouble();
// stocks
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// end write
// ---------------------affiche
public static void affiche(article art){
System.out.println("code : "+art.code);
System.out.println("nom : "+art.nom);
System.out.println("prix : "+art.prix);
System.out.println("Stock actuel : "+art.stockActuel);
System.out.println("Stock minimum : "+art.stockMinimum);
}// end poster
// ------------------------erreur
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// end error
}// fin class
Ecco alcuni esempi di esecuzione:
E:\data\serge\JAVA\random>java test6 2
code : b100
nom : pompe
prix : 65.0
Stock actuel : 6
Stock minimum : 0
E:\data\serge\JAVA\random>java.bat test6 20
Erreur lors de la lecture de l'enregistrement 20
4.11. Utilizzo delle espressioni regolari
4.11.1. Il pacchetto java.util.regex in Java
Il pacchetto java.util.regex consente l'uso di espressioni regolari. Queste consentono di convalidare il formato di una stringa. Ad esempio, è possibile verificare che una stringa che rappresenta una data sia nel formato gg/mm/aa. Per farlo, si utilizza un modello e si confronta la stringa con quel modello. In questo esempio, g, m e a devono essere cifre. Il modello per un formato di data valido è quindi "\d\d/\d\d/\d\d", dove il simbolo \d rappresenta una cifra. I simboli che possono essere utilizzati in un modello sono i seguenti (documentazione Microsoft):
Carattere | Descrizione |
\ | Indica che il carattere seguente è un carattere speciale o letterale. Ad esempio, "n" corrisponde al carattere "n". "\n" corrisponde a un carattere di nuova riga. La sequenza "\\" corrisponde a "\", mentre "\(" corrisponde a "(". |
^ | Corrisponde all'inizio dell'input. |
$ | Corrisponde alla fine dell'input. |
* | Corrisponde al carattere precedente zero o più volte. Pertanto, "zo*" corrisponde a "z" o "zoo". |
+ | Corrisponde al carattere precedente una o più volte. Pertanto, "zo+" corrisponde a "zoo", ma non a "z". |
? | Corrisponde al carattere precedente zero o una volta. Ad esempio, "a?ve?" corrisponde a "ve" in "lever". |
. | Corrisponde a qualsiasi singolo carattere, eccetto il carattere di nuova riga. |
(pattern) | Cerca il pattern e memorizza la corrispondenza. La sottostringa corrispondente può essere recuperata dalla collezione Matches risultante utilizzando Item [0]...[n]. Per trovare corrispondenze con caratteri all'interno di parentesi ( ), utilizzare "\(" o "\)". |
x|y | Corrisponde a x o y. Ad esempio, "z|foot" corrisponde a "z" o "foot". "(z|f)oo" corrisponde a "zoo" o "foo". |
{n} | n è un numero intero non negativo. Trova esattamente n occorrenze del carattere. Ad esempio, "o{2}" non trova "o" in "Bob", ma trova le prime due "o" in "fooooot". |
{n,} | n è un numero intero non negativo. Trova almeno n occorrenze del carattere. Ad esempio, "o{2,}" non trova "o" in "Bob", ma trova tutte le "o" in "fooooot". "o{1,}" equivale a "o+" e "o{0,}" equivale a "o*". |
{n,m} | m e n sono numeri interi non negativi. Trova da un minimo di n a un massimo di m occorrenze del carattere. Ad esempio, "o{1,3}" trova le prime tre "o" in "foooooot" e "o{0,1}" equivale a "o?". |
[xyz] | Insieme di caratteri. Trova uno qualsiasi dei caratteri specificati. Ad esempio, "[abc]" trova la "a" in "plat". |
[^xyz] | Insieme di caratteri negativo. Trova qualsiasi carattere non elencato. Ad esempio, "[^abc]" trova la "p" in "plat". |
[a-z] | Intervallo di caratteri. Corrisponde a qualsiasi carattere compreso nell'intervallo specificato. Ad esempio, "[a-z]" corrisponde a qualsiasi carattere alfabetico minuscolo compreso tra "a" e "z". |
[^m-z] | Intervallo di caratteri negativo. Trova qualsiasi carattere non compreso nell'intervallo specificato. Ad esempio, "[^m-z]" trova qualsiasi carattere non compreso tra "m" e "z". |
\b | Corrisponde a un confine di parola, ovvero alla posizione tra una parola e uno spazio. Ad esempio, "er\b" corrisponde a "er" in "lever", ma non a "er" in "verb". |
\B | Corrisponde a un confine che non rappresenta una parola. "en*t\B" corrisponde a "ent" in "bien entendu". |
\d | Corrisponde a un carattere che rappresenta una cifra. Equivalente a [0-9]. |
\D | Corrisponde a un carattere che non è una cifra. Equivalente a [^0-9]. |
\f | Corrisponde a un carattere di interruzione di riga. |
\n | Corrisponde a un carattere di nuova riga. |
\r | Equivalente al carattere di ritorno a capo. |
\s | Corrisponde a qualsiasi carattere di spaziatura, inclusi spazio, tabulazione, interruzione di pagina, ecc. Equivalente a "[ \f\n\r\t\v]". |
\S | Corrisponde a qualsiasi carattere non spazio. Equivalente a "[^ \f\n\r\t\v]". |
\t | Corrisponde a un carattere di tabulazione. |
\v | Corrisponde a un carattere di tabulazione verticale. |
\w | Corrisponde a qualsiasi carattere che rappresenta una parola, compreso il trattino basso. Equivalente a "[A-Za-z0-9_]". |
\W | Corrisponde a qualsiasi carattere che non rappresenti una parola. Equivalente a "[^A-Za-z0-9_]". |
\num | Corrisponde a num, dove num è un numero intero positivo. Si riferisce alle corrispondenze memorizzate. Ad esempio, "(.)\1" corrisponde a due caratteri identici consecutivi. |
|
Un elemento in un pattern può apparire una o più volte. Vediamo alcuni esempi che coinvolgono il simbolo \d, che rappresenta una singola cifra:
modello | significato |
\d | una cifra |
\d? | 0 o 1 cifra |
\d* | 0 o più cifre |
\d+ | 1 o più cifre |
\d{2} | 2 cifre |
\d{3,} | almeno 3 cifre |
\d{5,7} | da 5 a 7 cifre |
Ora immaginiamo un modello in grado di descrivere il formato previsto per una stringa:
stringa di destinazione | modello |
una data nel formato gg/mm/aa | \d{2}/\d{2}/\d{2} |
un'ora nel formato hh:mm:ss | \d{2}:\d{2}:\d{2} |
un numero intero senza segno | \d+ |
una sequenza di spazi, che può essere vuota | \s* |
un numero intero senza segno che può essere preceduto o seguito da spazi | \s*\d+\s* |
un numero intero che può essere con segno e preceduto o seguito da spazi | \s*[+|-]?\s*\d+\s* |
un numero reale senza segno che può essere preceduto o seguito da spazi | \s*\d+(.\d*)?\s* |
un numero reale che può essere con segno e preceduto o seguito da spazi | \s*[+|]?\s*\d+(.\d*)?\s* |
una stringa contenente la parola "just" | \bjuste\b |
È possibile specificare dove cercare il pattern nella stringa:
pattern | significato |
^motivo | il pattern inizia la stringa |
pattern$ | il pattern termina la stringa |
^pattern$ | il pattern inizia e termina la stringa |
pattern | il pattern viene cercato in qualsiasi punto della stringa, a partire dall'inizio. |
stringa di ricerca | pattern |
una stringa che termina con un punto esclamativo | !$ |
una stringa che termina con un punto | \.$ |
una stringa che inizia con la sequenza // | ^// |
una stringa costituita da una singola parola, facoltativamente seguita o preceduta da spazi | ^\s*\w+\s*$ |
una stringa composta da due parole, facoltativamente preceduta o seguita da spazi | ^\s*\w+\s*\w+\s*$ |
una stringa contenente la parola secret | \bsecret\b |
I sottopattern di un pattern possono essere "estratti". Pertanto, non solo possiamo verificare che una stringa corrisponda a un particolare pattern, ma possiamo anche estrarre da quella stringa gli elementi corrispondenti ai sottopattern del pattern che sono stati racchiusi tra parentesi. Ad esempio, se stiamo analizzando una stringa contenente una data nel formato dd/mm/yy e vogliamo anche estrarre gli elementi dd, mm e yy da quella data, useremmo il modello (\d\d)/(\d\d)/(\d\d).
4.11.2. Verifica della corrispondenza di una stringa con un dato modello
La classe Pattern consente di verificare se una stringa corrisponde a un dato modello. Per farlo, utilizzare il metodo statico
con: pattern: il modello da verificare, string: la stringa da confrontare con il modello. Il risultato è il valore booleano true se string corrisponde a pattern, false in caso contrario.
Ecco un esempio:
import java.io.*;
import java.util.regex.*;
// regular expression management
public class regex1 {
public static void main(String[] args){
// a regular expression template
String modèle1="^\\s*\\d+\\s*$";
// compare a copy with the model
String exemplaire1=" 123 ";
if (Pattern.matches(modèle1,exemplaire1)){
affiche("["+exemplaire1 + "] correspond au modèle ["+modèle1+"]");
}else{
affiche("["+exemplaire1 + "] ne correspond pas au modèle ["+modèle1+"]");
}//if
String exemplaire2=" 123a ";
if (Pattern.matches(modèle1,exemplaire2)){
affiche("["+exemplaire2 + "] correspond au modèle ["+modèle1+"]");
}else{
affiche("["+exemplaire2 + "] ne correspond pas au modèle ["+modèle1+"]");
}//if
}//hand
public static void affiche(String msg){
System.out.println(msg);
}//poster
}//class
e i risultati dell'esecuzione:
Si noti che nel modello "^\s*\d+\s*$", il carattere \ deve essere raddoppiato a causa della specifica interpretazione di questo carattere da parte di Java. Scriviamo quindi: String pattern1="^\\s*\\d+\\s*$";
4.11.3. Trovare tutti gli elementi di una stringa che corrispondono a un modello
Consideriamo il pattern "\d+" e la stringa " 123 456 789 ". Il pattern si trova in tre punti diversi della stringa. Le classi Pattern e Matcher consentono di recuperare le diverse occorrenze di un pattern in una stringa. La classe Pattern è quella che gestisce le espressioni regolari. Un'espressione regolare utilizzata più di una volta deve essere "compilata". Ciò accelera le ricerche di pattern nelle stringhe. Il metodo statico compile svolge questo compito:
Prende la stringa del pattern come parametro e restituisce un oggetto Pattern. Per confrontare il pattern di un oggetto Pattern con una stringa, utilizziamo la classe Matcher. Questa classe consente il confronto di un pattern con una stringa. Da un oggetto Pattern, è possibile ottenere un oggetto Matcher utilizzando il metodo matcher:
input è la stringa da confrontare con il modello.
Quindi, per confrontare il pattern "\d+" con la stringa " 123 456 789 ", è possibile creare un oggetto Matcher come segue:
Utilizzando l'oggetto résultats di cui sopra, possiamo recuperare le varie occorrenze del pattern nella stringa. Per farlo, utilizziamo i seguenti metodi della classe Matcher:
Il metodo find cerca nella stringa esplorata la prima occorrenza del pattern. Una seconda chiamata a find cercherà l'occorrenza successiva, e così via. Il metodo restituisce true se trova il pattern, false in caso contrario. La porzione della stringa corrispondente all'ultima occorrenza trovata da find si ottiene utilizzando il metodo group, mentre la sua posizione si ottiene utilizzando il metodo start. Quindi, continuando con l'esempio precedente, se vogliamo visualizzare tutte le occorrenze del pattern "\d+" nella stringa " 123 456 789 ", scriveremmo:
while(résultats.find()){
System.out.println("séquence " + résultats.group() + " trouvée en position " + résultats.start());
}//while
Il metodo reset consente di riportare l'oggetto Matcher all'inizio della stringa da confrontare con il pattern. In questo modo, il metodo find troverà nuovamente la prima occorrenza del pattern.
Ecco un esempio completo:
import java.io.*;
import java.util.regex.*;
// regular expression management
public class regex2 {
public static void main(String[] args){
// several occurrences of the model in the copy
String modèle2="\\d+";
Pattern regex2=Pattern.compile(modèle2);
String exemplaire3=" 123 456 789";
// search for model occurrences in the copy
Matcher matcher2=regex2.matcher(exemplaire3);
while(matcher2.find()){
affiche("séquence " + matcher2.group() + " trouvée en position " + matcher2.start());
}//while
}//Main
public static void affiche(String msg){
System.out.println(msg);
}//poster
}//class
Risultati dell'esecuzione:
Modèle=[\d+],exemplaire=[ 123 456 789 ]
Il y a 3 occurrences du modèle dans l'exemplaire
123 en position 2
456 en position 7
789 en position 12
4.11.4. Estrazione di parti di un modello
È possibile "estrarre" sottoinsiemi di un pattern. Pertanto, non solo possiamo verificare che una stringa corrisponda a un particolare pattern, ma possiamo anche estrarre da quella stringa gli elementi corrispondenti ai sottoinsiemi del pattern racchiusi tra parentesi. Ad esempio, se stiamo analizzando una stringa contenente una data nel formato dd/mm/yy e vogliamo anche estrarre gli elementi dd, mm e yy da quella data, useremmo il pattern (\d\d)/(\d\d)/(\d\d).
Esaminiamo il seguente esempio:
import java.io.*;
import java.util.regex.*;
// regular expression management
public class regex3 {
public static void main(String[] args){
// capture elements in the model
String modèle3="(\\d\\d):(\\d\\d):(\\d\\d)";
Pattern regex3=Pattern.compile(modèle3);
String exemplaire4="Il est 18:05:49";
// model checking
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// the copy corresponds to the model
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// display groups
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//for
}else{
// the copy does not correspond to the model
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
}//Main
public static void affiche(String msg){
System.out.println(msg);
}//poster
}//class
L'esecuzione di questo programma produce i seguenti risultati:
L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13
La nuova funzionalità si trova nel seguente frammento di codice:
// model checking
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// the copy corresponds to the model
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// display groups
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//for
}else{
// the copy does not correspond to the model
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
La stringa example4 viene confrontata con il pattern regex3 utilizzando il metodo find. Viene quindi trovata una corrispondenza per il pattern regex3 nella stringa example4. Se il pattern include sottoinsiemi racchiusi tra parentesi, questi sono accessibili tramite vari metodi della classe Matcher:
public int groupCount()
public String group(int group)
public int start(int group)
Il metodo groupCount restituisce il numero di sottogruppi trovati nel pattern, mentre group(i) restituisce il sottogruppo numero i. Questo si trova nella stringa nella posizione indicata da start(i). Quindi, nell'esempio:
L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13
La prima chiamata al metodo find troverà la stringa 18:05:49 e creerà automaticamente i tre sottoinsiemi definiti dalle parentesi nel pattern, ovvero 18, 05 e 49.
4.11.5. Un programma di apprendimento
Trovare l'espressione regolare che ci permette di verificare se una stringa corrisponde a un determinato modello può a volte essere una vera sfida. Il seguente programma ti permette di esercitarti. Richiede un modello e una stringa e poi indica se la stringa corrisponde o meno al modello.
import java.io.*;
import java.util.regex.*;
// regular expression management
public class regex4 {
public static void main(String[] args){
// data
String modèle=null,chaine=null;
Pattern regex=null;
BufferedReader IN=null;
Matcher résultats=null;
int nbOccurrences=0;
// error management
try{
// the user is asked for models and samples to compare with this one
while(true){
// iNPUTS
IN=new BufferedReader(new InputStreamReader(System.in));
// the model is requested
System.out.print("Tapez le modèle à tester ou fin pour arrêter :");
modèle=IN.readLine();
// finished?
if(modèle.trim().toLowerCase().equals("fin")) break;
// we create the regular expression
regex=Pattern.compile(modèle);
// the user is asked for the specimens to be compared with the model
while(true){
System.out.print("Tapez la chaîne à comparer au modèle ["+modèle+"] ou fin pour arrêter :");
chaine=IN.readLine();
// finished?
if(chaine.trim().toLowerCase().equals("fin")) break;
// create the matcher object
résultats=regex.matcher(chaine);
// search for occurrences of the
nbOccurrences=0;
while(résultats.find()){
// we have an occurrence
nbOccurrences++;
// we display it
System.out.println("J'ai trouvé la correspondance ["+résultats.group()
+"] en position "+résultats.start());
// display of sub-elements
if(résultats.groupCount()!=1){
for(int j=1;j<=résultats.groupCount();j++){
System.out.println("\tsous-élément ["+résultats.group(j)+"] en position "+
résultats.start(j));
}//for j
}//if
// next channel
}//while(résultats.find())
// was at least one occurrence found?
if(nbOccurrences==0){
System.out.println("Je n'ai pas trouvé de correspondance au modèle ["+modèle+"]");
}//if
// next model
}//while(true)
}//while(true)
}catch(Exception ex){
// error
System.err.println("Erreur : "+ex.getMessage());
// end with error
System.exit(1);
}//try-catch
// end
System.exit(0);
}//Main
}//class
Ecco un esempio di esecuzione:
Tapez le modèle à tester ou fin pour arrêter :\d+
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :123 456 789
J'ai trouvé la correspondance [123] en position 0
J'ai trouvé la correspondance [456] en position 4
J'ai trouvé la correspondance [789] en position 8
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :(\d\d):(\d\d)
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :14:15
abcd 17:18 xyzt
J'ai trouvé la correspondance [14:15] en position 0
sous-élément [14] en position 0
sous-élément [15] en position 3
J'ai trouvé la correspondance [17:18] en position 11
sous-élément [17] en position 11
sous-élément [18] en position 14
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :^\s*\d+\s*$
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter : 1456
J'ai trouvé la correspondance [ 1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :^\s*(\d+)\s*$
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :1456
J'ai trouvé la correspondance [1456] en position 0
sous-élément [1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :abcd 1
456
Je n'ai pas trouvé de correspondances
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :fin
Tapez le modèle à tester ou fin pour arrêter :fin
4.11.6. Il metodo split della classe Pattern
Consideriamo una stringa composta da campi separati da una stringa delimitatrice espressa tramite un'espressione regolare. Ad esempio, se i campi sono separati dal carattere , preceduto o seguito da un numero qualsiasi di spazi, l'espressione regolare che modella la stringa separatrice dei campi sarebbe "\s*,\s*". Il metodo split della classe Pattern ci permette di recuperare i campi in un array:
public String[] split(CharSequence input)
La stringa di input viene suddivisa in campi, separati da un separatore che corrisponde al pattern dell'oggetto Pattern corrente. Per recuperare i campi da una riga in cui il separatore di campo è una virgola preceduta o seguita da un numero qualsiasi di spazi, scriveremmo:
// a line
String ligne="abc ,, def , ghi";
// a model
Pattern modèle=Pattern.compile("\\s*,\\s*");
// decomposition of line into fields
String[] champs=modèle.split(ligne);
È possibile ottenere lo stesso risultato utilizzando il metodo split della classe String:
public String[] split(String regex)
Ecco un programma di prova:
import java.io.*;
import java.util.regex.*;
// regular expression management
public class split1 {
public static void main(String[] args){
// a line
String ligne="abc ,, def , ghi";
// a model
Pattern modèle=Pattern.compile("\\s*,\\s*");
// decomposition of line into fields
String[] champs=modèle.split(ligne);
// display
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
// another way of doing things
champs=ligne.split("\\s*,\\s*");
// display
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
}//Main
}//class
Risultati dell'esecuzione:
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
4.12. Esercizi
4.12.1. Esercizio 1
In Unix, i programmi vengono spesso richiamati come segue:
$ pg -o1 v1 v2 ... -o2 v3 v4 …
dove -oi rappresenta un'opzione e vi un valore associato a tale opzione. Vogliamo creare una classe di opzioni che analizzi la stringa di argomenti -o1 v1 v2 ... -o2 v3 v4 … al fine di costruire le seguenti entità:
ValidOptions | un dizionario (Hashtable) le cui chiavi sono le opzioni oi valide. Il valore associato alla chiave oi è un vettore (Vector) i cui elementi sono i valori v1, v2, … associati all'opzione -oi |
invalidOptions | dizionario (Hashtable) le cui chiavi sono le opzioni oi non valide. Il valore associato alla chiave oi è un vettore (Vector) i cui elementi sono i valori v1 v2 … associati all'opzione -oi |
optionsWithout | stringa (String) che elenca i valori vi non associati a un'opzione |
errore | un numero intero pari a 0 se non ci sono errori nell'elenco degli argomenti, altrimenti: 1: sono presenti parametri di chiamata non validi 2: ci sono opzioni non valide 4: sono presenti valori non associati alle opzioni Se sono presenti più tipi di errori, questi valori sono cumulativi. |
Un oggetto opzioni può essere costruito in 4 modi diversi:
public options (String arguments, String optionsAcceptable)
argomenti | gli argomenti della riga di comando -o1 v1 v2 ... -o2 v3 v4 … da analizzare |
optionsAcceptable | l'elenco delle opzioni accettabili |
Esempio di chiamata: options opt=new options("-u u1 u2 u3 -g g1 g2 -x","-u -g");
Qui, entrambi gli argomenti sono stringhe. Accetteremo i casi in cui queste stringhe sono state suddivise in parole e inserite in un array di stringhe. Ciò richiede tre costruttori aggiuntivi:
public options (String[] arguments, String optionsAcceptables)
public options (String arguments, String[] optionsAcceptables)
public options (String[] arguments, String[] optionsAcceptables)
La classe options avrà la seguente interfaccia (getter):
restituisce un riferimento all'array optionsValides costruito al momento della creazione dell'oggetto options
restituisce un riferimento all'array invalidOptions costruito al momento della creazione dell'oggetto options
Restituisce un riferimento alla stringa optionsWithout costruita al momento della creazione dell'oggetto options
Restituisce il valore dell'attributo error creato al momento della creazione dell'oggetto options
Se non ci sono errori, visualizza i valori degli attributi optionsValides, optionsInvalides e optionsSans; altrimenti, visualizza il numero dell'errore.
Ecco un programma di esempio:
import java.io.*;
//import options;
public class test1{
public static void main (String[] arg){
// inlet flow opening
String ligne;
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
affiche(e);
System.exit(1);
}
// read constructor arguments options(String, string)
String options=null;
String optionsAcceptables=null;
while(true){
System.out.print("Options : ");
try{
options=IN.readLine();
} catch (Exception e){
affiche(e);
System.exit(2);
}
if(options.length()==0) break;
System.out.print("Options acceptables: ");
try{
optionsAcceptables=IN.readLine();
} catch (Exception e){
affiche(e);
System.exit(2);
}
System.out.println(new options(options,optionsAcceptables));
}// end while
}//fine hand
public static void affiche(Exception e){
System.err.println("Erreur : "+e);
}
}//end of class
Alcuni risultati:
C:\Serge\java\options>java test1
Options : 1 2 3 -a a1 a2 -b b1 -c c1 c2 c3 -b b2 b3
Options acceptables: -a -b
Erreur 6
Options valides :(-b,b1,b2,b3) (-a,a1,a2)
Options invalides : (-c,c1,c2,c3)
Sans options : 1 2 3
4.12.2. Esercizio 2
Vogliamo creare una classe stringtovector che ci consenta di trasferire il contenuto di un oggetto String in un oggetto Vector. Questa classe deriverebbe dalla classe Vector:
e avrebbe il seguente costruttore:
private void stringtovector(String S, String separateur, int[] tChampsVoulus,
boolean strict){
// crée un vecteur avec les champs de la chaîne S
// celle-ci est constituée de champs séparés par separateur
// si séparateur=null, la chaîne ne forme qu'un seul champ
// seuls les champs dont les index sont dans le tableau tChampsVoulus
// sont désirés. Les index commencent à 1
// si tChampsvoulus=null ou de taille nulle, on prend tous les champs
// si strict=vrai, tous les champs désirés doivent être présents
La classe avrebbe il seguente attributo privato:
Questo attributo viene impostato dal costruttore precedente con i seguenti valori:
0: la creazione è andata a buon fine
4: mancano alcuni campi obbligatori nonostante strict=true
La classe avrà anche due metodi:
che restituisce il valore dell'attributo privato error.
che visualizza il valore dell'oggetto nella forma (errore, elemento 1, elemento 2, …) dove gli elementi i sono gli elementi del vettore costruito dalla stringa.
Un programma di prova potrebbe essere simile a questo:
import java.io.*;
//import stringtovector;
public class essai2{
public static void main(String arg[]){
int[] T1={1,3};
System.out.println(new stringtovector("a : b : c :d:e",":",T1,true).identite());
int[] T2={1,3,7};
System.out.println(new stringtovector("a : b : c :d:e",":",T2,true).identite());
int [] T3={1,4,7};
System.out.println(new stringtovector("a : b : c :d:e",":",T3,false).identite());
System.out.println(new stringtovector("a : b : c :d:e","",T1,false).identite());
System.out.println(new stringtovector("a : b : c :d:e",null,T1,false).identite());
int[] T4={1};
System.out.println(new stringtovector("a : b : c :d:e","!",T4,true).identite());
int[] T5=null;
System.out.println(new stringtovector("a : b : c :d:e",":",T5,true).identite());
System.out.println(new stringtovector("a : b : c :d:e",null,T5,true).identite());
int[] T6=new int[0];
System.out.println(new stringtovector("a : b : c :d:e","",T6,true).identite());
int[] T7={1,3,4};
System.out.println(new stringtovector("a b c d e"," ",T6,true).identite());
}
}
I risultati:
(0,a,c)
(4,a,c)
(0,a,d)
(0,a : b : c :d:e)
(0,a : b : c :d:e)
(0,a : b : c :d:e)
(0,a,b,c,d,e)
(0,a : b : c :d:e)
(0,a : b : c :d:e)
(0,a,b,c,d,e)
Alcuni consigli:
- Per suddividere la stringa S in campi, usa il metodo split della classe String.
- Inserisci i campi di S in un dizionario D indicizzato dal numero del campo
- Recupera dal dizionario D solo quei campi le cui chiavi (indici) sono presenti nell'array tChampsVoulus.
4.12.3. Esercizio 3
Vogliamo aggiungere il seguente costruttore alla classe stringtovector:
public stringtovector(String S, String separateur, String sChampsVoulus,boolean strict){
// crée un vecteur avec les champs de la chaîne S
// celle-ci est constituée de champs séparés par separateur
// si séparateur=null, la chaîne ne forme qu'un seul champ
// seuls les champs dont les index sont dans sChampsVoulus sont désirés
// les index commencent à 1
// si sChampsvoulus=null ou "", on prend tous les champs
// si strict=vrai, tous les champs désirés doivent être présents
L'elenco dei campi desiderati è quindi una stringa (String) anziché un array di interi (int[]). All'attributo privato error della classe può essere assegnato un nuovo valore:
2: la stringa degli indici dei campi desiderati non è corretta
Ecco un programma di esempio:
import java.io.*;
//import stringtovector;
public class essai1{
public static void main(String arg[]){
String champs=null;
System.out.println(new stringtovector("a: b :c :d:e ",":","1 3",true).identite());
System.out.println(new stringtovector("a: b :c :d:e ",":","1 3 7",true).identite());
System.out.println(new stringtovector("a: b :c :d:e ",":","1 4 7",false).identite());
System.out.println(new stringtovector("a: b :c :d:e ","","1 3",false).identite());
System.out.println(new stringtovector("a: b :c :d:e ",null,"1 3",false).identite());
System.out.println(new stringtovector("a: b :c :d:e ","!","1",true).identite());
System.out.println(new stringtovector("a: b :c :d:e ",":","",true).identite());
System.out.println(new stringtovector("a: b :c :d:e ",":",champs,true).identite());
System.out.println(new stringtovector("a: b :c :d:e ",null,champs,true).identite());
System.out.println(new stringtovector("a: b :c :d:e ","","",true).identite());
System.out.println(new stringtovector("a: b :c :d:e ",":","1 !",true).identite());
System.out.println(new stringtovector("a b c d e "," ","1 3",false).identite());
}
}
Alcuni risultati:
(0,a,c)
(4,a,c)
(0,a,d)
(0,a: b :c :d:e)
(0,a: b :c :d:e)
(0,a: b :c :d:e)
(0,a,b,c,d,e)
(0,a,b,c,d,e)
(0,a: b :c :d:e)
(0,a: b :c :d:e)
(2)
(0,a,c)
Alcuni consigli:
- È necessario tornare al caso del costruttore precedente trasferendo i campi dalla stringa sChampsVoulus in un array di interi. Per farlo, suddividere sChampsVoulus in campi utilizzando un oggetto StringTokenizer, il cui attributo countTokens fornirà il numero di campi ottenuti. È quindi possibile creare un array di interi della dimensione corretta e riempirlo con i campi ottenuti.
- Per determinare se un campo è un numero intero, utilizzare il metodo Integer.parseInt per convertire il campo in un numero intero e gestire l'eccezione che verrà generata se questa conversione non è possibile.
4.12.4. Esercizio 4
Vogliamo creare una classe filetovector che ci consenta di trasferire il contenuto di un file di testo in un oggetto Vector. Questa classe deriverebbe dalla classe Vector:
e avrebbe il seguente costruttore:
// --------------------- constructeur
public filetovector(String nomFichier, String separateur, int [] tChampsVoulus,boolean strict, String tagCommentaire){
// creates a vector with the lines in the nomFichier text file
// lines are made up of fields separated by separators
// if separator=null, the line forms a single field
// only fields whose indexes are in tChampsVoulus are desired
// indexes start at 1
// if tChampsvoulus=null or empty, all fields are taken
// if strict=true, all desired fields must be present
// if this is not the case, the line is not stored and its index
// is placed in the vector lignesErronees
// white lines are ignored
// as well as lines beginning with tagCommentaire if tagCommentaire != null
La classe avrebbe i seguenti attributi privati:
L'attributo errore viene impostato dal costruttore precedente con i seguenti valori:
0: la creazione è andata a buon fine
1: impossibile aprire il file da elaborare
4: mancano alcuni campi obbligatori anche se strict=true
8: si è verificato un errore di I/O durante l'elaborazione del file
L'attributo lignesErronees è un vettore i cui elementi sono i numeri delle righe errate sotto forma di stringhe di caratteri. Una riga è considerata errata se non è in grado di fornire i campi richiesti quando strict=true.
La classe disporrà inoltre di due metodi:
che restituisce il valore dell'attributo privato error.
che visualizza il valore dell'oggetto nella forma (errore, elemento 1, elemento 2 …,(l1,l2,…)) dove gli elementi i sono gli elementi del vettore costruito dal file e li sono i numeri delle righe errate.
Ecco un test di esempio:
import java.io.*;
//import filetovector;
public class test2{
public static void main(String arg[]){
int[] T1={1,3};
System.out.println(new filetovector("data.txt",":",T1,false,"#").identite());
System.out.println(new filetovector("data.txt",":",T1,true,"#").identite());
System.out.println(new filetovector("data.txt","",T1,false,"#").identite());
System.out.println(new filetovector("data.txt",null,T1,false,"#").identite());
int[] T2=null;
System.out.println(new filetovector("data.txt",":",T2,false,"#").identite());
System.out.println(new filetovector("data.txt",":",T2,false,"").identite());
int[] T3=new int[0];
System.out.println(new filetovector("data.txt",":",T3,false,null).identite());
}
}
Risultati dell'esecuzione:
[0,(0,a,c) (0,1,3) (0,azerty,cvf) (0,s)]
[4,(0,a,c) (0,1,3) (0,azerty,cvf),[5]]
[0,(0,a:b:c:d:e) (0,1 :2 : 3: 4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a:b:c:d:e) (0,1 :2 : 3: 4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Alcuni consigli
-
Il file di testo viene elaborato riga per riga. La riga viene suddivisa in campi utilizzando la classe stringtovector discussa in precedenza.
-
Gli elementi del vettore creato dal file di testo sono quindi oggetti di tipo stringtovector.
-
Il metodo identite di filetovector può avvalersi del metodo stringtovector.identite() per visualizzare i propri elementi, nonché del metodo Vector.toString() per visualizzare il numero di eventuali righe errate.
4.12.5. Esercizio 5
Vogliamo aggiungere il seguente costruttore alla classe filetovector:
public filetovector(String nomFichier, String separateur, String sChampsVoulus,
boolean strict, String tagCommentaire){
// creates a vector with the lines in the nomFichier text file
// lines are made up of fields separated by separators
// if separator=null, the line forms a single field
// only fields whose indexes are in tChampsVoulus are desired
// indexes start 1
// if sChampsvoulus=null or empty, all fields are taken
// if strict=true, all desired fields must be present
// if this is not the case, the line is not stored and its index
// is placed in the vector lignesErronees
// white lines are ignored
// as well as lines beginning with tagCommentaire if tagCommentaire != null
L'elenco degli indici per i campi obbligatori è ora contenuto in una stringa (String) anziché in un array di numeri interi.
L'attributo privato error può avere un valore aggiuntivo:
2: la stringa degli indici dei campi desiderati non è corretta
Ecco un test di esempio:
import java.io.*;
//import filetovector;
public class test1{
public static void main(String arg[]){
System.out.println(new filetovector("data.txt",":","1 3",false,"#").identite());
System.out.println(new filetovector("data.txt",":","1 3",true,"#").identite());
System.out.println(new filetovector("data.txt","","1 3",false,"#").identite());
System.out.println(new filetovector("data.txt",null," 1 3",false,"#").identite());
String S2=null;
System.out.println(new filetovector("data.txt",":",S2,false,"#").identite());
System.out.println(new filetovector("data.txt",":",S2,false,"").identite());
String S3="";
System.out.println(new filetovector("data.txt",":",S3,false,null).identite());
}
}
[0,(0,a,c) (0,1,3) (0,azerty,cvf) (0,s)][4,(0,a,c) (0,1,3) (0,azerty,cvf),[5]]
[0,(0,a:b:c:d:e) (0,1 :2 : 3: 4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a:b:c:d:e) (0,1 :2 : 3: 4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]
- Convertiamo la stringa sChampsVoulus in un array di interi tChampVoulus per riportarla al caso del costruttore precedente.