4. Classes comumente utilizadas em Java
Neste capítulo, apresentamos várias classes Java comumente utilizadas. Estas possuem inúmeros atributos, métodos e construtores. Em cada caso, apresentamos apenas uma pequena parte das classes. Detalhes sobre estas estão disponíveis na ajuda do Java, que apresentamos agora.
4.1. A documentação
Se tiver instalado o Sun JDK na pasta <jdk>, a documentação está disponível na pasta <jdk>\docs:

Por vezes, tem um JDK mas não tem documentação. Esta pode ser encontrada no site da Sun em http://www.sun.com. Na pasta docs, encontrará um ficheiro index.html, que serve como ponto de partida para a ajuda do JDK:


O link «API & Language» acima dá acesso às classes Java. O link «Demos/Tutorials» é particularmente útil para encontrar exemplos de programas Java. Vamos seguir o link «API & Language»:

Vamos seguir o link Java 2 Platform API:

Esta página é o verdadeiro ponto de partida para a documentação das classes. Pode criar um atalho para ela para acesso rápido. O URL é <jdk>\docs\api\index.html. Contém links para centenas de classes Java no JDK. Quando se está a começar, o principal desafio é descobrir o que estas diferentes classes fazem. Inicialmente, este recurso só é útil se souber o nome da classe sobre a qual deseja obter informações. Também pode usar os nomes das classes como guia, uma vez que estes indicam normalmente a finalidade da classe.
Vamos dar um exemplo e procurar informações sobre a classe Vector, que implementa uma matriz dinâmica. Basta procurar o link da classe Vector na lista de classes no painel esquerdo:

e clique no link para ver a definição da classe:

Aí encontrará
- a hierarquia em que a classe se encontra, neste caso java.util.Vector
- a lista de campos (atributos) da classe
- a lista de construtores
- a lista de métodos
Nas secções seguintes, apresentamos várias classes. Encorajamos o leitor a verificar sistematicamente a definição completa das classes utilizadas.
4.2. Classes de teste
Os exemplos a seguir utilizam, por vezes, as classes Pessoa e Professor. Apresentamos aqui as suas definições.
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;
}
}
A classe Teacher deriva da classe Person e é definida da seguinte forma:
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+")";
}
}
Também utilizaremos uma classe «student» derivada da classe «person» e definida da seguinte forma:
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. A classe String
A classe String representa cadeias de caracteres. Seja *name* uma variável de cadeia de caracteres:
*String name;*
name é uma referência a um objeto que ainda não foi inicializado. Pode ser inicializado de duas maneiras:
**name = "horse"** ou **name = new String("horse")**
Ambos os métodos são equivalentes. Se mais tarde escrevermos name="fish", name passará a referir-se a um novo objeto. O antigo objeto String("horse") é perdido, e a memória que ocupava será recuperada.
A classe String possui muitos atributos e métodos. Aqui estão alguns:
public char charAt(int i) | retorna o caractere no índice i da string, onde o primeiro caractere tem o índice 0. Assim, `String("horse").charAt(3)` é igual a 'h' |
public int compareTo(string2) | string1.compareTo(string2) compara string1 com string2 e retorna 0 se string1 = string2, 1 se string1 > string2 e -1 se string1 < string2 |
public boolean equals(Object anObject) | string1.equals(string2) retorna true se string1 = string2, false caso contrário |
public String toLowerCase() | string1.toLowerCase() converte string1 em minúsculas |
public String toUpperCase() | string1.toUpperCase() converte string1 em maiúsculas |
public String trim() | string1.trim() remove os espaços à esquerda e à direita de string1 |
public String substring(int beginIndex, int endIndex) | String("chapeau").subString(2,4) devolve a string "ape" |
public char[] toCharArray() | converte os caracteres da string numa matriz de caracteres |
int length() | número de caracteres na string |
int indexOf(String string2) | retorna a primeira ocorrência de string2 na string atual, ou -1 se string2 não estiver presente |
int indexOf(String string2, int startIndex) | Retorna a primeira ocorrência de string2 na string atual, ou -1 se string2 não for encontrada. A pesquisa começa no caractere na posição startIndex. |
int lastIndexOf(String string2) | Retorna a última posição de string2 na string atual, ou -1 se string2 não estiver presente |
boolean startsWith(String string2) | retorna true se a string atual começar com string2 |
boolean endsWith(String string2) | retorna true se a string atual terminar com string2 |
boolean matches(String regex) | retorna true se a string atual corresponder à expressão regular regex. |
String[] split(String regex) | A string atual é composta por campos separados por uma sequência de caracteres correspondente à expressão regular regex. O método split recupera os campos para uma matriz. |
String replace(char oldChar, char newChar) | Substitui o caractere oldChar pelo caractere newChar na string atual. |
Aqui está um programa de exemplo:
// 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 os resultados obtidos:
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. A Classe Vector
Um vetor é uma matriz dinâmica cujos elementos são referências a objetos. Trata-se, portanto, de uma matriz de objetos cujo tamanho pode variar ao longo do tempo, o que não é possível com as matrizes estáticas que vimos até agora. Aqui estão alguns campos, construtores ou métodos desta classe:
public Vector() | constrói um vetor vazio |
public final int size() | número de elementos no vetor |
public final void addElement(Object obj) | adiciona o objeto referenciado por obj ao vetor |
public final Object elementAt(int index) | referência ao objeto no índice da matriz - os índices começam em 0 |
public final Enumeration elements() | o conjunto de elementos na matriz como uma enumeração |
public final Object firstElement() | referência ao primeiro elemento da matriz |
public final Object lastElement() | referência ao último elemento do vetor |
public final boolean isEmpty() | retorna true se a matriz estiver vazia |
public final void removeElementAt(int index) | remove o elemento no índice |
public final void removeAllElements() | limpa a matriz de todos os seus elementos |
public final String toString() | retorna uma string que representa a matriz |
Aqui está um programa de teste:
// 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
Vamos compilar este programa:
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
Vamos executar o ficheiro 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)
A partir de agora, não repetiremos mais o processo de compilação e execução dos programas de teste. Basta repetir o que foi feito acima.
4.5. A classe ArrayList
A classe ArrayList é análoga à classe Vector. A principal diferença entre elas surge apenas quando são utilizadas simultaneamente por várias threads. Os métodos de sincronização de threads para aceder a um Vector ou a um ArrayList são diferentes. Fora deste caso, ambas podem ser utilizadas de forma intercambiável. Aqui estão alguns campos, construtores ou métodos desta classe:
ArrayList() | constrói uma matriz vazia |
int size() | número de elementos na matriz |
void add(Object obj) | adiciona o objeto referenciado por obj à matriz |
void add(int index, Object obj) | adiciona o objeto referenciado por obj à matriz na posição index |
Object get(int index) | referência ao objeto na posição index na matriz — os índices começam em 0 |
boolean isEmpty() | retorna true se a matriz estiver vazia |
void remove(int index) | remove o elemento no índice |
void clear() | limpa a matriz de todos os seus elementos |
Object[] toArray() | converte a matriz dinâmica numa matriz padrão |
String toString() | retorna uma string que representa a matriz |
Aqui está um programa de teste:
// 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
Os resultados obtidos são os mesmos de antes.
4.6. A Classe Arrays
A classe java.util.Arrays fornece acesso a métodos estáticos que permitem realizar várias operações em matrizes, nomeadamente a ordenação e a pesquisa de elementos. Aqui estão alguns desses métodos:
static void sort(array) | ordena a matriz utilizando a ordem implícita do tipo de dados da matriz, sejam números ou cadeias de caracteres. |
static void sort(Object[] array, Comparator C) | Ordena a matriz utilizando a função de comparação C para comparar elementos |
static int binarySearch(array, element) | Retorna a posição do elemento na matriz ou, caso contrário, um valor <0. A matriz deve estar previamente ordenada. |
static int binarySearch(Object[] array, Object element, Comparator C) | Igual ao anterior, mas utiliza a função de comparação C para comparar dois elementos na matriz. |
Aqui está um primeiro exemplo:
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
Vamos examinar este programa. A função principal cria um objeto sort2. O construtor da classe sort2 é o seguinte:
// 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
A matriz a ser ordenada é uma matriz de objetos Person. A classe Person está definida como privada dentro da classe sort2. O método estático sort da classe Arrays não sabe como ordenar uma matriz de objetos Person, pelo que somos obrigados aqui a utilizar a forma void sort(Object[] obj, Comparator C). Comparator é uma interface que define apenas um método:
e que deve devolver 0 se o1=o2, -1: se o1 < o2, +1: se o1 > o2. No protótipo void sort(Object[] obj, Comparator C), o segundo argumento C deve ser um objeto que implemente a interface Comparator. No construtor sort2, escolhemos o objeto atual this:
Isto obriga-nos a fazer duas coisas:
- indicar que a classe sort2 implementa a interface Comparator
- escrever a função compare na classe sort2.
Fica assim:
// 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
Para comparar dois objetos Pessoa, usamos aqui a idade (podíamos ter usado o nome).
Os resultados da execução são os seguintes:
Podíamos ter adotado uma abordagem diferente para implementar a interface 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
A instrução de ordenação ficou da seguinte forma:
// sorting the people table
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compare
}//class
);
O segundo parâmetro do método compare deve ser um objeto que implemente a interface Comparator. Aqui, criamos esse objeto utilizando new java.util.Comparator(), e o texto que se segue a {…} define a classe a partir da qual o objeto é criado. Esta é designada por classe anónima, uma vez que não possui nome. Nesta classe anónima, que deve implementar a interface Comparator, definimos o método compare dessa interface. Este método simplesmente chama o método compare1 da classe sort2. Voltamos então ao caso anterior.
A classe sort2 já não implementa a interface Comparator. Por conseguinte, a sua declaração passa a ser:
Agora testamos o método binarySearch da classe Arrays utilizando o seguinte exemplo:
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
Aqui, procedemos de forma um pouco diferente dos exemplos anteriores. Os dois objetos Comparator necessários para os métodos sort e binarySearch foram criados e atribuídos às variáveis 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
;
Uma pesquisa binária na matriz friends é realizada duas vezes no construtor sort4:
O método de pesquisa recebe todos os parâmetros necessários para chamar o método 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
O método binarySearch funciona com o comparador comparator2, que, por sua vez, chama o método compare2 da classe sort4. O método devolve a posição do nome pesquisado na matriz, se este existir, ou um número <0 caso contrário. O método compare2 é utilizado para comparar um objeto Person com um nome do 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
Ao contrário do método sort, o método binarySearch não recebe dois objetos Person, mas sim um objeto Person e um objeto String, nessa ordem. O primeiro parâmetro é um elemento da matriz friends e o segundo é o nome da pessoa que se pretende encontrar.
4.7. A classe Enumeration
Enumeration é uma interface, não uma classe. Possui os seguintes métodos:
public abstract boolean hasMoreElements() | retorna true se a enumeração ainda tiver elementos |
public abstract Object nextElement() | retorna uma referência ao próximo elemento na enumeração |
Como se utiliza uma enumeração? Geralmente, desta forma:
Enumeration e=… // an enumeration object is retrieved
while(e.hasMoreElements()){
// use e.nextElement() element
}
Aqui está um exemplo:
// 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
Os seguintes resultados são obtidos:
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. A classe HashTable
A classe HashTable permite-lhe implementar um dicionário. Um dicionário pode ser visto como uma matriz de duas colunas:
chave | valor |
chave1 | valor1 |
chave2 | valor2 |
.. | ... |
As chaves são únicas, ou seja, não podem existir duas chaves idênticas. Os principais métodos e propriedades da classe Hashtable são os seguintes:
public Hashtable() | construtor - cria um dicionário vazio |
public int size() | número de elementos no dicionário — onde um elemento é um par (chave, valor) |
public Object put(Object key, Object value) | adiciona o par (chave, valor) ao dicionário |
public Object get(Object key) | recupera o objeto associado à chave key ou null, caso a chave key não exista |
public boolean containsKey(Object key) | true se a chave existir no dicionário |
public boolean contains(Object value) | true se o valor value existir no dicionário |
public Enumeration keys() | retorna as chaves do dicionário como uma enumeração |
public Object remove(Object key) | remove o par (chave, valor) onde chave=chave |
public String toString() | identifica o dicionário |
Aqui está um exemplo:
// 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
Os resultados são os seguintes:
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. Ficheiros de texto
4.9.1. Escrita
Para escrever num ficheiro, é necessário um fluxo de escrita. Pode utilizar a classe FileWriter para este efeito. Os seguintes construtores são comumente utilizados:
FileWriter(String fileName) | cria um ficheiro com o nome fileName — pode então escrever nele — qualquer ficheiro existente com o mesmo nome é substituído |
FileWriter(String fileName, boolean append) | igual ao anterior — qualquer ficheiro existente com o mesmo nome pode ser utilizado abrindo-o no modo de adição (append=true) |
A classe FileWriter fornece vários métodos para escrever num ficheiro, métodos herdados da classe Writer. Para escrever num ficheiro de texto, é preferível utilizar a classe PrintWriter, cujos construtores mais utilizados são os seguintes:
PrintWriter(Writer out) | o argumento é do tipo Writer, ou seja, um fluxo de escrita (para um ficheiro, através da rede, etc.) |
PrintWriter(Writer out, boolean autoflush) | O mesmo que acima. O segundo argumento controla o buffer de linhas. Quando definido como false (o valor predefinido), as linhas escritas no ficheiro passam por um buffer na memória. Quando o buffer está cheio, é gravado no ficheiro. Isto melhora o acesso ao disco. Dito isto, este comportamento é por vezes indesejável, particularmente ao escrever através de uma rede. |
Os métodos úteis da classe PrintWriter são os seguintes:
void print(Type T) | escreve os dados T (String, int, ….) |
void println(Type T) | igual ao anterior, terminando com um caractere de nova linha |
void flush() | esvazia o buffer se não estiver no modo de esvaziamento automático |
void close() | fecha o fluxo de escrita |
Aqui está um programa que escreve algumas linhas num ficheiro de texto:
// 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
O ficheiro de saída gerado pelo programa é o seguinte:
4.9.2. Leitura
Para ler o conteúdo de um ficheiro, é necessário um fluxo de leitura associado ao ficheiro. Para tal, pode utilizar a classe FileReader e o seguinte construtor:
FileReader(String filename) | abre um fluxo de leitura a partir do ficheiro especificado. Lança uma exceção se a operação falhar. |
A classe FileReader possui vários métodos para ler a partir de um ficheiro, métodos herdados da classe Reader. Para ler linhas de texto a partir de um ficheiro de texto, é preferível utilizar a classe BufferedReader com o seguinte construtor:
BufferedReader(Reader in) | abre um fluxo de leitura em buffer a partir de um fluxo de entrada in. Este fluxo do tipo Reader pode provir do teclado, de um ficheiro, da rede, etc. |
Os métodos úteis da classe BufferedReader são os seguintes:
int read() | lê um caractere |
String readLine() | lê uma linha de texto |
int read(char[] buffer, int offset, int size) | Lê size caracteres do ficheiro e coloca-os na matriz de buffer a partir da posição offset. |
void close() | fecha o fluxo de leitura |
Aqui está um programa que lê o conteúdo do ficheiro criado anteriormente:
// 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
A execução do programa produz os seguintes resultados:
4.9.3. Guardar um objeto pessoa
Aplicamos o que acabámos de ver para dotar a classe Person de um método que nos permita guardar os atributos de uma pessoa num ficheiro. Adicionamos o método saveAttributes à definição da classe Person:
// ------------------------------
// sauvegarde dans fichier texte
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
Antes de definir a classe Person, não se esqueça de importar o pacote java.io:
O método saveAttributes recebe um único parâmetro: o fluxo PrintWriter no qual deve escrever. Um programa de teste pode ter o seguinte aspeto:
// 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
Vamos compilar e executar este programa:
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. Ficheiros binários
4.10.1. A classe RandomAccessFile
A classe RandomAccessFile permite-lhe gerir ficheiros binários, em particular aqueles com uma estrutura fixa, como os encontrados em C/C++. Aqui estão alguns métodos e construtores úteis:
RandomAccessFile(String filename, String mode) | construtor - abre o ficheiro especificado no modo especificado. O modo pode ser um dos seguintes: r: abrir para leitura rw: abrir para leitura e escrita |
void writeTTT(TTT value) | escreve o valor no ficheiro. TTT representa o tipo de valor. A representação em memória do valor é escrita tal como está no ficheiro. Assim, existem writeBoolean, writeByte, writeInt, writeDouble, writeLong, writeFloat, etc. Para escrever uma cadeia de caracteres, utilize writeBytes(String string). |
TTT readTTT() | Lê e devolve um valor do tipo TTT. Exemplos incluem readBoolean, readByte, readInt, readDouble, readLong, readFloat, etc. O método read() lê um byte. |
long length() | tamanho do ficheiro em bytes |
long getFilePointer() | posição atual do ponteiro do ficheiro |
void seek(long pos) | define o cursor do ficheiro no byte pos |
4.10.2. A classe Article
Todos os exemplos a seguir utilizarão a seguinte 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
A classe Item em Java acima é equivalente à seguinte estrutura em C
struct article{
char code[4];
char nom[20];
double prix;
int stockActuel;
int stockMinimum;
}//structure
Desta forma, limitaremos o código a 4 caracteres e o nome a 20.
4.10.3. Criar um registo
O programa a seguir grava um registo num ficheiro chamado «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
O programa seguinte permite-nos verificar se a execução foi bem-sucedida.
4.10.4. Ler um registo
// 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
Os resultados da execução são os seguintes:
E:\data\serge\JAVA\random>java test2
code : a100
nom : velo
prix : 1000.8
Stock actuel : 100
Stock minimum : 10
Recuperamos com sucesso o registo que foi gravado pelo programa de gravação.
4.10.5. Conversão de texto para binário
O programa a seguir é uma extensão do programa de gravação de registos. Agora, gravamos vários registos num ficheiro binário chamado data.bin. Os dados são retirados do seguinte ficheiro 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
O programa seguinte permite-lhe verificar se este funcionou corretamente.
4.10.6. Conversão de binário para texto
O programa a seguir lê o conteúdo do ficheiro binário data.bin criado anteriormente e grava o seu conteúdo no ficheiro de texto data.text. Se tudo correr bem, o ficheiro data.text deverá ser idêntico ao ficheiro original 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
Aqui está um exemplo de execução:
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. Acesso direto aos registos
Este último programa demonstra a capacidade de aceder diretamente a registos num ficheiro binário. Apresenta o registo do ficheiro data.bin cujo número é passado como parâmetro, sendo que o primeiro registo tem o número 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
Aqui estão alguns exemplos de execução:
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. Utilização de expressões regulares
4.11.1. O pacote java.util.regex no Java
O pacote java.util.regex permite a utilização de expressões regulares. Estas permitem-lhe validar o formato de uma cadeia de caracteres. Por exemplo, pode verificar se uma cadeia de caracteres que representa uma data está no formato dd/mm/aa. Para tal, utiliza-se um padrão e compara-se a cadeia de caracteres com esse padrão. Neste exemplo, d, m e y devem ser dígitos. O padrão para um formato de data válido é, portanto, "\d\d/\d\d/\d\d", onde o símbolo \d representa um dígito. Os símbolos que podem ser utilizados num padrão são os seguintes (documentação da Microsoft):
Caractere | Descrição |
\ | Designa o caractere seguinte como um caractere especial ou literal. Por exemplo, "n" corresponde ao caractere "n". "\n" corresponde a um caractere de nova linha. A sequência "\\" corresponde a "\", enquanto "\(" corresponde a "(". |
^ | Corresponde ao início da entrada. |
$ | Corresponde ao fim da entrada. |
* | Corresponde ao caractere anterior zero ou mais vezes. Assim, «zo*» corresponde a «z» ou «zoo». |
+ | Corresponde ao caractere anterior uma ou mais vezes. Assim, «zo+» corresponde a «zoo», mas não a «z». |
? | Corresponde ao caractere anterior zero ou uma vez. Por exemplo, "a?ve?" corresponde a "ve" em "lever". |
. | Corresponde a qualquer caractere único, exceto o caractere de nova linha. |
(padrão) | Procura o padrão e armazena a correspondência. A subcadeia correspondente pode ser recuperada da coleção Matches resultante utilizando Item [0]...[n]. Para encontrar correspondências com caracteres dentro de parênteses ( ), utilize "\(" ou "\)". |
x|y | Corresponde a x ou a y. Por exemplo, "z|foot" corresponde a "z" ou a "foot". "(z|f)oo" corresponde a "zoo" ou a "foo". |
{n} | n é um número inteiro não negativo. Corresponde exatamente a n ocorrências do caractere. Por exemplo, "o{2}" não corresponde a "o" em "Bob", mas corresponde aos dois primeiros "o"s em "fooooot". |
{n,} | n é um número inteiro não negativo. Corresponde a pelo menos n ocorrências do caractere. Por exemplo, "o{2,}" não corresponde a "o" em "Bob", mas corresponde a todos os "o"s em "fooooot". "o{1,}" é equivalente a "o+" e "o{0,}" é equivalente a "o*". |
{n,m} | m e n são números inteiros não negativos. Corresponde a, no mínimo, n e, no máximo, m ocorrências do caractere. Por exemplo, "o{1,3}" corresponde aos primeiros três "o"s em "foooooot" e "o{0,1}" é equivalente a "o?". |
[xyz] | Conjunto de caracteres. Corresponde a qualquer um dos caracteres especificados. Por exemplo, "[abc]" corresponde a "a" em "plat". |
[^xyz] | Conjunto de caracteres negativo. Corresponde a qualquer caractere não listado. Por exemplo, "[^abc]" corresponde a "p" em "plat". |
[a-z] | Intervalo de caracteres. Corresponde a qualquer caractere no intervalo especificado. Por exemplo, "[a-z]" corresponde a qualquer caractere alfabético minúsculo entre "a" e "z". |
[^m-z] | Intervalo de caracteres negativo. Corresponde a qualquer caractere que não esteja no intervalo especificado. Por exemplo, "[^m-z]" corresponde a qualquer caractere que não esteja entre "m" e "z". |
\b | Corresponde a um limite de palavra, ou seja, a posição entre uma palavra e um espaço. Por exemplo, "er\b" corresponde a "er" em "lever", mas não a "er" em "verb". |
\B | Corresponde a um limite que não representa uma palavra. "en*t\B" corresponde a "ent" em "bien entendu". |
\d | Corresponde a um caractere que representa um dígito. Equivalente a [0-9]. |
\D | Corresponde a um caractere que não seja um dígito. Equivalente a [^0-9]. |
\f | Corresponde a um caractere de quebra de linha. |
\n | Corresponde a um caractere de nova linha. |
\r | Equivalente a um caractere de retorno de carro. |
\s | Corresponde a qualquer espaço em branco, incluindo espaço, tabulação, quebra de página, etc. Equivalente a "[ \f\n\r\t\v]". |
\S | Corresponde a qualquer caractere que não seja um espaço em branco. Equivalente a "[^ \f\n\r\t\v]". |
\t | Corresponde a um caractere de tabulação. |
\v | Corresponde a um caractere de tabulação vertical. |
\w | Corresponde a qualquer caractere que represente uma palavra, incluindo o sublinhado. Equivalente a "[A-Za-z0-9_]". |
\W | Corresponde a qualquer caractere que não represente uma palavra. Equivalente a "[^A-Za-z0-9_]". |
\num | Corresponde a num, onde num é um número inteiro positivo. Refere-se a correspondências armazenadas. Por exemplo, "(.)\1" corresponde a dois caracteres idênticos consecutivos. |
|
Um elemento num padrão pode aparecer uma ou várias vezes. Vejamos alguns exemplos envolvendo o símbolo \d, que representa um único dígito:
padrão | significado |
\d | um dígito |
\d? | 0 ou 1 dígito |
\d* | 0 ou mais dígitos |
\d+ | 1 ou mais dígitos |
\d{2} | 2 dígitos |
\d{3,} | pelo menos 3 dígitos |
\d{5,7} | entre 5 e 7 dígitos |
Agora, imaginemos um modelo capaz de descrever o formato esperado para uma cadeia de caracteres:
cadeia de caracteres alvo | padrão |
uma data no formato dd/mm/aa | \d{2}/\d{2}/\d{2} |
uma hora no formato hh:mm:ss | \d{2}:\d{2}:\d{2} |
um inteiro sem sinal | \d+ |
uma sequência de espaços, que pode estar vazia | \s* |
um inteiro sem sinal que pode ser precedido ou seguido por espaços | \s*\d+\s* |
um inteiro que pode ser assinado e precedido ou seguido por espaços | \s*[+|-]?\s*\d+\s* |
um número real sem sinal que pode ser precedido ou seguido por espaços | \s*\d+(.\d*)?\s* |
um número real que pode ser assinado e precedido ou seguido por espaços | \s*[+|]?\s*\d+(.\d*)?\s* |
uma cadeia de caracteres contendo a palavra «just» | \bjuste\b |
Pode especificar onde procurar o padrão na string:
padrão | significado |
^padrão | o padrão inicia a cadeia |
padrão$ | o padrão termina a cadeia |
^padrão$ | o padrão inicia e termina a cadeia |
padrão | o padrão é procurado em qualquer parte da cadeia, começando pelo início. |
cadeia de pesquisa | padrão |
uma cadeia que termine com um ponto de exclamação | !$ |
uma cadeia que termina com um ponto | \.$ |
uma sequência que começa com // | ^// |
uma cadeia composta por uma única palavra, opcionalmente seguida ou precedida por espaços | ^\s*\w+\s*$ |
uma cadeia composta por duas palavras, opcionalmente seguida ou precedida por espaços | ^\s*\w+\s*\w+\s*$ |
uma cadeia que contém a palavra secret | \bsecret\b |
Os subpadrões de um padrão podem ser «extraídos». Assim, não só podemos verificar se uma cadeia corresponde a um determinado padrão, como também podemos extrair dessa cadeia os elementos correspondentes aos subpadrões do padrão que foram colocados entre parênteses. Por exemplo, se estivermos a analisar uma cadeia de caracteres que contenha uma data no formato dd/mm/aa e também quisermos extrair os elementos dd, mm e aa dessa data, usaríamos o padrão (\d\d)/(\d\d)/(\d\d).
4.11.2. Verificar se uma string corresponde a um determinado padrão
A classe Pattern permite verificar se uma string corresponde a um determinado padrão. Para fazer isso, use o método estático
com: padrão: o padrão a verificar, string: a string a comparar com o padrão. O resultado é o valor booleano true se a string corresponder ao padrão, false caso contrário.
Eis um exemplo:
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 os resultados da execução:
Note que no padrão "^\s*\d+\s*$", o caractere \ deve ser duplicado devido à interpretação específica do Java para este caractere. Por isso, escrevemos: String pattern1="^\\s*\\d+\\s*$";
4.11.3. Encontrar todos os elementos de uma string que correspondam a um padrão
Considere o padrão "\d+" e a cadeia " 123 456 789 ". O padrão é encontrado em três locais diferentes na cadeia. As classes Pattern e Matcher permitem-lhe recuperar as diferentes ocorrências de um padrão numa cadeia. A classe Pattern é a classe que lida com expressões regulares. Uma expressão regular utilizada mais do que uma vez precisa de ser «compilada». Isto acelera as pesquisas de padrões nas cadeias de caracteres. O método estático compile realiza esta tarefa:
Recebe a cadeia de caracteres do padrão como parâmetro e devolve um objeto Pattern. Para comparar o padrão de um objeto Pattern com uma cadeia de caracteres, utilizamos a classe Matcher. Esta classe permite a comparação de um padrão com uma cadeia de caracteres. A partir de um objeto Pattern, é possível obter um objeto Matcher utilizando o método matcher:
input é a string que deve ser comparada com o padrão.
Assim, para comparar o padrão "\d+" com a string " 123 456 789 ", pode criar um objeto Matcher da seguinte forma:
Usando o objeto résultats acima, podemos recuperar as várias ocorrências do padrão na string. Para isso, usamos os seguintes métodos da classe Matcher:
O método find procura na string explorada a primeira ocorrência do padrão. Uma segunda chamada ao find irá procurar a ocorrência seguinte, e assim sucessivamente. O método devolve true se encontrar o padrão, false caso contrário. A parte da string correspondente à última ocorrência encontrada pelo método find é obtida através do método group, e a sua posição através do método start. Assim, continuando o exemplo anterior, se quisermos exibir todas as ocorrências do padrão "\d+" na string " 123 456 789 ", escreveríamos:
while(résultats.find()){
System.out.println("séquence " + résultats.group() + " trouvée en position " + résultats.start());
}//while
O método reset permite-lhe reiniciar o objeto Matcher para o início da cadeia de caracteres que está a ser comparada com o padrão. Desta forma, o método find irá então encontrar novamente a primeira ocorrência do padrão.
Aqui está um exemplo 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
Resultados da execução:
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. Extrair partes de um padrão
É possível «extrair» subconjuntos de um padrão. Assim, não só podemos verificar se uma cadeia de caracteres corresponde a um determinado padrão, como também podemos extrair dessa cadeia os elementos correspondentes aos subconjuntos do padrão que foram colocados entre parênteses. Por exemplo, se estivermos a analisar uma cadeia de caracteres que contenha uma data no formato dd/mm/aa e também quisermos extrair os elementos dd, mm e aa dessa data, usaríamos o padrão (\d\d)/(\d\d)/(\d\d).
Vamos examinar o seguinte exemplo:
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
A execução deste programa produz os seguintes resultados:
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
A nova funcionalidade encontra-se no seguinte trecho de código:
// 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+"]");
}
A string example4 é comparada com o padrão regex3 utilizando o método find. É então encontrada uma correspondência para o padrão regex3 na string example4. Se o padrão incluir subconjuntos entre parênteses, estes são acessíveis através de vários métodos da classe Matcher:
public int groupCount()
public String group(int group)
public int start(int group)
O método groupCount devolve o número de subgrupos encontrados no padrão, e group(i) devolve o subgrupo número i. Este encontra-se na cadeia de caracteres na posição indicada por start(i). Assim, no exemplo:
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
A primeira chamada ao método find irá localizar a cadeia 18:05:49 e criar automaticamente os três subconjuntos definidos pelos parênteses no padrão, nomeadamente 18, 05 e 49.
4.11.5. Um programa de aprendizagem
Encontrar a expressão regular que nos permite verificar se uma string corresponde a um determinado padrão pode, por vezes, ser um verdadeiro desafio. O programa seguinte permite-lhe praticar. Pede um padrão e uma string e, em seguida, indica se a string corresponde ou não ao padrão.
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
Aqui está um exemplo de execução:
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. O método split da classe Pattern
Considere uma cadeia composta por campos separados por uma cadeia delimitadora expressa através de uma expressão regular. Por exemplo, se os campos forem separados pelo caractere , precedido ou seguido por qualquer número de espaços, a expressão regular que modela a cadeia separadora de campos seria "\s*,\s*". O método split da classe Pattern permite-nos recuperar os campos numa matriz:
public String[] split(CharSequence input)
A string de entrada é dividida em campos, que são separados por um separador que corresponde ao padrão do objeto Pattern atual. Para recuperar os campos de uma linha em que o separador de campos é uma vírgula precedida ou seguida por qualquer número de espaços, escreveríamos:
// 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);
Pode obter o mesmo resultado utilizando o método split da classe String:
public String[] split(String regex)
Aqui está um programa de teste:
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
Resultados da execução:
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
4.12. Exercícios
4.12.1. Exercício 1
No Unix, os programas são frequentemente chamados da seguinte forma:
$ pg -o1 v1 v2 ... -o2 v3 v4 …
onde -oi representa uma opção e vi um valor associado a essa opção. Pretendemos criar uma classe de opções que analise a cadeia de argumentos -o1 v1 v2 ... -o2 v3 v4 … para construir as seguintes entidades:
ValidOptions | um dicionário (Hashtable) cujas chaves são as opções -oi válidas. O valor associado à chave -oi é um vetor (Vector) cujos elementos são os valores v1, v2, … associados à opção -oi |
invalidOptions | dicionário (Hashtable) cujas chaves são as opções oi inválidas. O valor associado à chave oi é um vetor (Vector) cujos elementos são os valores v1, v2, … associados à opção -oi |
optionsWithout | string (String) que lista os valores vi não associados a uma opção |
error | um inteiro igual a 0 se não houver erros na lista de argumentos; caso contrário: 1: existem parâmetros de chamada inválidos 2: existem opções inválidas 4: existem valores não associados a opções Se houver vários tipos de erros, estes valores são cumulativos. |
Um objeto de opções pode ser construído de 4 maneiras diferentes:
public options (String arguments, String optionsAcceptable)
arguments | os argumentos da linha de comando -o1 v1 v2 ... -o2 v3 v4 … a serem analisados |
optionsAcceptable | a lista de opções aceitáveis |
Exemplo de chamada: options opt=new options("-u u1 u2 u3 -g g1 g2 -x","-u -g");
Aqui, ambos os argumentos são cadeias de caracteres. Aceitaremos casos em que estas cadeias tenham sido divididas em palavras e colocadas numa matriz de cadeias de caracteres. Isto requer três construtores adicionais:
public options (String[] arguments, String optionsAcceptables)
public options (String arguments, String[] optionsAcceptables)
public options (String[] arguments, String[] optionsAcceptables)
A classe options terá a seguinte interface (getters):
retorna uma referência à matriz optionsValides construída quando o objeto options foi criado
retorna uma referência à matriz invalidOptions construída quando o objeto options foi criado
Retorna uma referência à string optionsWithout construída quando o objeto options foi criado
Retorna o valor do atributo error criado quando o objeto options foi criado
Se não houver erros, exibe os valores dos atributos optionsValides, optionsInvalides e optionsSans; caso contrário, exibe o número do erro.
Eis um programa de exemplo:
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
Alguns resultados:
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. Exercício 2
Queremos criar uma classe stringtovector que nos permita transferir o conteúdo de um objeto String para um objeto Vector. Esta classe seria derivada da classe Vector:
e teria o seguinte construtor:
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
A classe teria o seguinte atributo privado:
Este atributo é definido pelo construtor anterior com os seguintes valores:
0: a construção foi bem-sucedida
4: faltam alguns campos obrigatórios, apesar de strict=true
A classe também terá dois métodos:
que devolve o valor do atributo privado error.
que exibe o valor do objeto na forma (erro, elemento 1, elemento 2, …) onde os elementos i são os elementos do vetor construído a partir da string.
Um programa de teste poderia ter o seguinte aspecto:
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());
}
}
Os resultados:
(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)
Algumas dicas:
- Para dividir a cadeia S em campos, utilize o método split da classe String.
- Coloque os campos de S num dicionário D indexado pelo número do campo
- Recupere do dicionário D apenas os campos cujas chaves (índices) estejam na matriz tChampsVoulus.
4.12.3. Exercício 3
Queremos adicionar o seguinte construtor à 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
A lista de campos desejados está, portanto, numa string (String) em vez de numa matriz de inteiros (int[]). Ao atributo privado error da classe pode ser atribuído um novo valor:
2: a cadeia de caracteres com os índices dos campos desejados está incorreta
Aqui está um programa de exemplo:
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());
}
}
Alguns resultados:
(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)
Algumas dicas:
- É necessário voltar ao caso do construtor anterior, transferindo os campos da string sChampsVoulus para uma matriz de inteiros. Para tal, divida sChampsVoulus em campos utilizando um objeto StringTokenizer, cujo atributo countTokens fornecerá o número de campos obtidos. Pode então criar uma matriz de inteiros com o tamanho correto e preenchê-la com os campos obtidos.
- Para determinar se um campo é um inteiro, utilize o método Integer.parseInt para converter o campo num inteiro e trate a exceção que será lançada se esta conversão não for possível.
4.12.4. Exercício 4
Queremos criar uma classe filetovector que nos permita transferir o conteúdo de um ficheiro de texto para um objeto Vector. Esta classe seria derivada da classe Vector:
e teria o seguinte construtor:
// --------------------- 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
A classe teria os seguintes atributos privados:
O atributo error é definido pelo construtor anterior com os seguintes valores:
0: a construção foi bem-sucedida
1: não foi possível abrir o ficheiro a ser processado
4: faltam alguns campos obrigatórios, apesar de strict=true
8: ocorreu um erro de E/S durante o processamento do ficheiro
O atributo lignesErronees é um vetor cujos elementos são os números das linhas com erros, na forma de cadeias de caracteres. Uma linha é considerada errada se não conseguir fornecer os campos solicitados quando strict=true.
A classe terá também dois métodos:
que devolve o valor do atributo privado error.
que exibe o valor do objeto na forma (erro, elemento 1, elemento 2 …,(l1,l2,…)), em que os elementos i são os elementos do vetor construído a partir do ficheiro e li são os números das linhas com erros.
Aqui está um exemplo de teste:
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());
}
}
Resultados da execução:
[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)]
Algumas dicas
-
O ficheiro de texto é processado linha a linha. A linha é dividida em campos utilizando a classe stringtovector discutida anteriormente.
-
Os elementos do vetor criado a partir do ficheiro de texto são, portanto, objetos do tipo stringtovector.
-
O método identite de filetovector pode recorrer ao método stringtovector.identite() para exibir os seus elementos, bem como ao método Vector.toString() para exibir os números de quaisquer linhas com erros.
4.12.5. Exercício 5
Queremos adicionar o seguinte construtor à 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
A lista de índices para os campos obrigatórios está agora numa string (String) em vez de uma matriz de inteiros.
O atributo de erro privado pode ter um valor adicional:
2: a cadeia de caracteres dos índices de campo pretendidos está incorreta
Aqui está um exemplo de teste:
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)]
- Vamos converter a cadeia sChampsVoulus numa matriz de inteiros tChampVoulus para a trazer de volta ao caso do construtor anterior.