4. Classes de uso comum
Apresentamos neste capítulo algumas classes Java de uso comum. Elas possuem diversos atributos, métodos e construtores. Em cada caso, apresentamos apenas uma pequena parte das classes. Os detalhes sobre elas estão disponíveis na documentação do Java, que apresentamos a seguir.
4.1. A documentação
Se você instalou o JDK da Sun na pasta <jdk>, a documentação está disponível na pasta <jdk>\docs:

Às vezes, temos um jdk, mas sem documentação. Ela pode ser encontrada no site da Sun http://www.sun.com. Na pasta docs, encontra-se um arquivo index.html, que é o ponto de partida da ajuda do JDK:


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

Vamos acessar o link Java 2 Platform API:

Esta página é o verdadeiro ponto de partida da documentação sobre as classes. É possível criar um atalho para ela para ter acesso rápido. O URL está em <jdk>\docs\api\index.html. Nela, encontram-se links para centenas de classes Java do JDK. Quando se está começando, a principal dificuldade é saber o que essas diferentes classes fazem. Inicialmente, portanto, essa ajuda só tem utilidade se você souber o nome da classe sobre a qual deseja obter informações. Também é possível se orientar pelos nomes das classes, que normalmente indicam a função da classe.
Vamos dar um exemplo e procurar informações sobre a classe Vector, que implementa um array dinâmico. Basta procurar na lista de classes do painel esquerdo o link da classe Vector:

e clicar no link para obter a definição da classe:

Lá você encontrará
- a hierarquia na qual a classe está inserida, neste caso java.util.Vector
- a lista de campos (atributos) da classe
- a lista de construtores
- a lista de métodos
A seguir, apresentamos diversas classes. Convidamos o leitor a verificar sistematicamente a definição completa das classes utilizadas.
4.2. As classes de teste
Os exemplos a seguir utilizam, em alguns casos, as classes personne e enseignant. Recordamos aqui suas definições.
public class personne{
// sobrenome, nome, idade
private String prenom;
private String nom;
private int age;
// construtor 1
public personne(String P, String N, int age){
this.prenom=P;
this.nom=N;
this.age=age;
}
// construtor 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+")";
}
// acessórios
public String getPrenom(){
return prenom;
}
public String getNom(){
return nom;
}
public int getAge(){
return age;
}
//modificadores
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 enseignant é derivada da classe personne e está definida da seguinte forma:
class enseignant extends personne{
// atributos
private int section;
// construtor
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 etudiant derivada da classe personne 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 nom uma variável de cadeia de caracteres:
String nome;
nom é uma referência a um objeto ainda não inicializado. É possível inicializá-lo de duas maneiras:
nom="cavalo" ou nom=new String("cavalo")
Os dois métodos são equivalentes. Se, posteriormente, escrevermos nom="peixe", ***nom*** passará a referenciar um novo objeto. O objeto antigo *String("cheval")* será perdido e o espaço de memória que ele ocupava será recuperado.
A classe String possui diversos atributos e métodos. Aqui estão alguns deles:
public char charAt(int i) | retorna o caractere i da string, sendo que o primeiro caractere tem índice 0. Assim, String("cavalo").charAt(3) é igual a 'v' |
public int compareTo(cadeia2) | chaine1.compareTo(chaine2) compara chaine1 com chaine2 e retorna 0 se chaine1 = chaine2, 1 se chaine1 > chaine2 e -1 se chaine1 < chaine2 |
public boolean equals(Object anObject) | chaine1.equals(cadeia2) retorna verdadeiro se cadeia1 = cadeia2, falso caso contrário |
public String toLowerCase() | chaine1.toLowerCase() converte string1 em letras minúsculas |
public String toUpperCase() | chaine1.toUpperCase() converte a string1 em maiúsculas |
public String trim() | chaine1.trim() remove os espaços no início e no final de string1 |
public String substring(int beginIndex, int endIndex) | String("chapeau").subString(2,4) retorna a string "ape" |
public char[] toCharArray() | permite colocar os caracteres da string em uma matriz de caracteres |
int length() | número de caracteres da string |
int indexOf(String string2) | retorna a primeira posição de chaine2 na string atual ou -1 se chaine2 não estiver presente |
int indexOf(String string2, int startIndex) | retorna a primeira posição de chaine2 na string atual ou -1 se chaine2 não estiver presente. A busca começa a partir do caractere nº startIndex. |
int lastIndexOf(String string2) | retorna a última posição de chaine2 na string atual ou -1 se chaine2 não estiver presente |
boolean startsWith(String string2) | retorna verdadeiro se a string atual começar com chaine2 |
boolean endsWith(String string2) | retorna verdadeiro se a string atual terminar com chaine2 |
boolean matches(String regex) | retorna verdadeiro 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 modelada pela expressão regular regex. O método split permite recuperar os campos em um array. |
String replace(char oldChar, char newChar) | substitui, na string atual, o caractere oldChar pelo caractere newChar. |
Aqui está um programa de exemplo:
// importações
import java.io.*;
public class string1{
// uma classe de demonstração
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]+"]");
}//para
affiche("(\" abc \").trim()=["+" abc ".trim()+"]");
}//Main
// exibe
public static void affiche(String msg){
// exibe msg
System.out.println(msg);
}//exibe
}//classe
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 é um array dinâmico cujos elementos são referências a objetos. Trata-se, portanto, de um array de objetos cujo tamanho pode variar ao longo do tempo, o que não é possível com os arrays estáticos que vimos até agora. Aqui estão alguns campos, construtores ou métodos dessa classe:
public Vector() | cria um vetor vazio |
public final int size() | número de elementos do 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 nº index do vetor — os índices começam em 0 |
public final Enumeration elements() | o conjunto de elementos do vetor na forma de uma enumeração |
public final Object firstElement() | referência ao primeiro elemento do vetor |
public final Object lastElement() | referência ao último elemento do vetor |
public final boolean isEmpty() | retorna verdadeiro se o vetor estiver vazio |
public final void removeElementAt(int index) | remove o elemento com índice index |
public final void removeAllElements() | esvazia o vetor de todos os seus elementos |
public final String toString() | retorna uma string de identificação do vetor |
Aqui está um programa de teste:
// as classes importadas
import java.util.*;
public class test1{
// o programa principal main - estático - método de classe
public static void main(String arg[]){
// a criação de objetos (instâncias de 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());
// polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// um vetor
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());
}
} // fim de `main`
}// fim da classe
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 arquivo 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)
Daqui em diante, 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. Ela difere desta essencialmente apenas quando é utilizada simultaneamente por várias threads de execução. Os métodos de sincronização de threads para o acesso a um Vector ou a um ArrayList diferem. Fora desse caso, pode-se utilizar indistintamente um ou outro. Aqui estão alguns campos, construtores ou métodos dessa classe:
ArrayList() | cria uma lista vazia |
int size() | número de elementos da lista |
void add(Object obj) | adiciona o objeto referenciado por obj à lista |
void add(int index, Object obj) | adiciona o objeto referenciado por obj à matriz na posição index |
Object get(int index) | referência do objeto nº index da tabela — os índices começam em 0 |
boolean isEmpty() | retorna verdadeiro se a matriz estiver vazia |
void remove(int index) | remove o elemento com índice index |
void clear() | esvazia a matriz de todos os seus elementos |
Object[] toArray() | converte a matriz dinâmica em uma matriz clássica |
String toString() | retorna uma string de identificação da matriz |
Aqui está um programa de teste:
// as classes importadas
import java.util.*;
public class test1{
// o programa principal main - estático - método de classe
public static void main(String arg[]){
// criação de objetos (instâncias de 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);
// polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2);
personne p3=(personne)et;
System.out.println("p3="+p3);
// um vetor
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);
}
} // fim de `main`
}// fim da classe
Os resultados obtidos são os mesmos de antes.
4.6. A classe Arrays
A classe java.util.Arrays oferece acesso a métodos estáticos que permitem diversas operações em matrizes, especialmente ordenações e pesquisas de elementos. Aqui estão alguns desses métodos:
static void sort(matriz) | ordena tableau utilizando, para isso, a ordem implícita do tipo de dados da matriz, seja número ou cadeias de caracteres. |
static void sort (Object[] array, Comparator C) | ordena o array tableau utilizando a função de comparação C para comparar os elementos |
static int binarySearch(matriz, elemento) | retorna a posição de élément em tableau ou um valor <0 caso contrário. A matriz deve estar previamente ordenada. |
static int binarySearch(Object[] array, Object elemento, Comparator C) | O mesmo, mas utiliza a função de comparação C para comparar dois elementos da matriz. |
Aqui está um primeiro exemplo:
import java.util.*;
public class sort2 implements Comparator{
// uma classe privada interna
private class personne{
private String nom;
private int age;
public personne(String nom, int age){
this.nom=nom; // nome da pessoa
this.age=age; // sua idade
}
// obter a idade
public int getAge(){
return age;
}
// identidade da pessoa
public String toString(){
return ("["+nom+","+age+"]");
}
}; // classe “pessoa”
// fabricante
public sort2() {
// uma tabela de pessoas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// classificação da tabela de pessoas
Arrays.sort(amis,this);
// verificação
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//criador
// a função que compara pessoas
public int compare(Object o1, Object o2){
// deve retornar
// -1 se o1 for “menor que” o2
// 0 se o1 for “igual a” o2
// +1 se o1 for “maior que” 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;
}//compara
// função de teste
public static void main(String[] arg){
new sort2();
}//mão
}//classe
Vamos examinar este programa. A função main cria um objeto *sort2*. O construtor da classe *sort2* é o seguinte:
// fabricante
public sort2() {
// uma tabela de pessoas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// classificação da lista de pessoas
Arrays.sort(amis,this);
// verificação
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//criador
A tabela a ser classificada é uma tabela de objetos personne. A classe personne é definida de forma privada (private) dentro da classe sort2. O método estático sort da classe Arrays não sabe como classificar um array de objetos personne; portanto, somos obrigados a usar aqui a forma void sort(Object[] obj, Comparator C). Comparator é uma interface que define apenas um método:
e que deve retornar 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:
Isso nos obriga a fazer duas coisas:
- indicar que a classe sort2 implementa a interface Comparator
- escrever a função compare na classe sort2.
Ela é a seguinte:
// a função que compara pessoas
public int compare(Object o1, Object o2){
// deve retornar
// -1 se o1 for “menor que” o2
// 0 se o1 for “igual a” o2
// +1 se o1 for “maior que” 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;
}//compara
Para comparar dois objetos personne, utiliza-se aqui a idade (também se poderia ter usado o nome).
Os resultados da execução são os seguintes:
Poderíamos ter procedido de maneira diferente para implementar a interface Comparator:
import java.util.*;
public class sort2 {
// uma classe privada interna
private class personne{
…….
}; // classe pessoa
// construtor
public sort2() {
// um array de pessoas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// classificação da matriz de pessoas
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compara
}//classe
);
// verificação
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//criador
// a função que compara pessoas
public int compare1(Object o1, Object o2){
// deve retornar
// -1 se o1 for “menor que” o2
// 0 se o1 for “igual a” o2
// +1 se o1 for “maior que” 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;
}//compara1
// main
public static void main(String[] arg){
new sort2();
}//main
}//classe
A instrução de classificação ficou da seguinte forma:
// classificação da tabela de pessoas
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//comparar
}//turma
);
O segundo parâmetro do método sort deve ser um objeto que implemente a interface Comparator. Aqui, criamos esse objeto por meio de new java.util.Comparator(), e o texto que se segue {…} define a classe da qual estamos criando um objeto. Chamamos isso de classe anônima, pois ela não possui nome. Nessa classe anônima, que deve implementar a interface Comparator, definimos o método compare dessa interface. Este método se limita a chamar o método compare1 da classe sort2. Assim, voltamos ao caso anterior.
A classe sort2 não implementa mais a interface Comparator. Portanto, sua declaração passa a ser:
Agora, testamos o método binarySearch da classe Arrays no exemplo a seguir:
import java.util.*;
public class sort4 {
// uma classe privada interna
private class personne{
// atributos
private String nom;
private int age;
// construtor
public personne(String nom, int age){
this.nom=nom; // nome da pessoa
this.age=age; // sua idade
}
// obter o nome
public String getNom(){
return nom;
}
// recuperar a idade
public int getAge(){
return age;
}
// identidade da pessoa
public String toString(){
return ("["+nom+","+age+"]");
}
}; // classe da pessoa
// fabricante
public sort4() {
// uma tabela de pessoas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// comparadores
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compara
}//classe
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//compara
}//classifica
;
// classificação da tabela de pessoas
Arrays.sort(amis,comparateur1);
// verificação
for(int i=0;i<3;i++)
System.out.println(amis[i]);
// pesquisas
cherche("milou",amis,comparateur2);
cherche("xx",amis,comparateur2);
}//criador
// a função que compara pessoas
public int compare1(Object o1, Object o2){
// deve retornar
// -1 se o1 for “menor que” o2
// 0 se o1 for “igual a” o2
// +1 se o1 for “maior que” 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;
}//compara1
// a função que compara uma pessoa a um nome
public int compare2(Object o1, Object o2){
// o1 é uma pessoa
// o2 é uma String, o nome nom2 de uma pessoa
// deve retornar
// -1 se o1.nom for “menor que” nom2
// 0 se o1.nom for “igual a” nom2
// +1 se o1.nom for “maior que” nome2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//compara2
public void cherche(String ami,personne[] amis, Comparator comparateur){
// procura amigo na tabela de amigos
int position=Arrays.binarySearch(amis,ami,comparateur);
// encontrado?
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//procura
// mão
public static void main(String[] arg){
new sort4();
}//mão
}//turma
Aqui, procedemos de maneira 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 comparateur1 e comparateur2.
// comparadores
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compara
}//classe
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//compara
}//classe
;
Uma pesquisa dicotômica na tabela amis é realizada duas vezes no construtor de sort4:
O método cherche recebe todos os parâmetros necessários para chamar o método binarySearch:
public void cherche(String ami,personne[] amis, Comparator comparateur){
// procura amigo na lista de amigos
int position=Arrays.binarySearch(amis,ami,comparateur);
// encontrado?
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//procura
O método binarySearch opera com o comparador comparateur2, que, por sua vez, utiliza o método compare2 da classe sort4. O método rend retorna a posição do nome procurado na tabela, caso ele exista, ou um número <0, caso contrário. O método compare2 serve para comparar um objeto personne com um nome do tipo String.
// a função que compara uma pessoa a um nome
public int compare2(Object o1, Object o2){
// o1 é uma pessoa
// o2 é uma String, o nome nom2 de uma pessoa
// deve retornar
// -1 se o1.nom for “menor que” nome2
// 0 se o1.nom for “igual a” nome2
// +1 se o1.nom for “maior que” nome2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//compara2
Ao contrário do método sort, o método binarySearch não recebe dois objetos personne, mas sim um objeto personne e um objeto String, nessa ordem. O primeiro parâmetro é um elemento da matriz amis; o segundo, o nome da pessoa procurada.
4.7. A classe Enumeration
Enumeration é uma interface e não uma classe. Ela possui os seguintes métodos:
public abstract boolean hasMoreElements() | retorna verdadeiro se a enumeração ainda tiver elementos |
public abstract Object nextElement() | retorna a referência do próximo elemento da enumeração |
Como se utiliza uma enumeração? Geralmente, desta forma:
Enumeration e=… // recupera-se um objeto de enumeração
while(e.hasMoreElements()){
// utilizar o elemento e.nextElement()
}
Veja um exemplo:
// as classes importadas
import java.util.*;
public class test1{
// o programa principal main – estático – método de classe
public static void main(String arg[]){
// criação de objetos (instâncias de 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());
// polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// um vetor
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());
}
// uma enumeração
Enumeration E=V.elements();
i=0;
while(E.hasMoreElements()){
p2=(personne) E.nextElement();
System.out.println("V["+i+"]="+p2.toString());
i++;
}
}// fim de main
}//fim da classe
Obtêm-se os seguintes resultados:
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 implementar um dicionário. Pode-se considerar um dicionário como uma tabela com duas colunas:
chave | valor |
chave1 | valor1 |
chave2 | valor2 |
.. | ... |
As chaves são únicas, c.a.d. Não pode haver 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 — sendo que 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) | verdadeiro se a chave key existir no dicionário |
public boolean contains(Object value) | verdadeiro se o valor value existir no dicionário |
public Enumeration keys() | retorna as chaves do dicionário na forma de uma enumeração |
public Object remove(Object key) | remove o par (chave, valor) em que chave = key |
public String toString() | identifica o dicionário |
Veja um exemplo:
// as classes importadas
import java.util.*;
public class test1{
// o programa principal main - estático - método de classe
public static void main(String arg[]){
// a criação de objetos (instâncias de 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());
// polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// um dicionário
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++;
}
}//fim de `main`
}//fim da classe
Os resultados obtidos 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. Os arquivos de texto
4.9.1. Gravação
Para gravar em um arquivo, é necessário dispor de um fluxo de gravação. Para isso, pode-se utilizar a classe FileWriter. Os construtores mais utilizados são os seguintes:
FileWriter(String fileName) | cria o arquivo com o nome fileName — em seguida, é possível gravar nele — um eventual arquivo com o mesmo nome será sobrescrito |
FileWriter(String fileName, boolean append) | idem — um eventual arquivo com o mesmo nome pode ser utilizado abrindo-o no modo de acréscimo (append=true) |
A classe FileWriter oferece vários métodos para gravar em um arquivo, métodos herdados da classe Writer. Para gravar em um arquivo de texto, é preferível usar a classe PrintWriter, cujos construtores mais utilizados são os seguintes:
PrintWriter(Writer out) | o argumento é do tipo Writer, c.a.d. um fluxo de gravação (em um arquivo, na rede, …) |
PrintWriter(Writer out, boolean autoflush) | O mesmo. O segundo argumento controla o buffer das linhas. Quando é definido como falso (valor padrão), as linhas gravadas no arquivo passam por um buffer na memória. Quando este fica cheio, o conteúdo é gravado no arquivo. Isso melhora o acesso ao disco. No entanto, às vezes, esse comportamento é indesejável, especialmente ao gravar na rede. |
Os métodos úteis da classe PrintWriter são os seguintes:
void print(Type T) | grava o dado T (String, int, …) |
void println(Type T) | faz o mesmo, terminando com um caractere de fim de linha |
void flush() | esvazia o buffer se não estivermos no modo autoflush |
void close() | fecha o fluxo de gravação |
Aqui está um programa que grava algumas linhas em um arquivo de texto:
// importações
import java.io.*;
public class ecrire{
public static void main(String[] arg){
// abertura do arquivo
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// gravação no arquivo
try{
fic.println("Jean,Dupont,27");
fic.println("Pauline,Garcia,24");
fic.println("Gilles,Dumond,56");
} catch (Exception e){
Erreur(e,3);
}
// fechamento do arquivo
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// fim da função
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Erro
}//classe
O arquivo out obtido na execução é o seguinte:
4.9.2. Ler
Para ler o conteúdo de um arquivo, é necessário dispor de um fluxo de leitura associado ao arquivo. Para isso, pode-se utilizar a classe FileReader e o seguinte construtor:
FileReader(String nomeDoArquivo) | abre um fluxo de leitura a partir do arquivo indicado. Lança uma exceção se a operação falhar. |
A classe FileReader possui vários métodos para ler um arquivo, métodos herdados da classe Reader. Para ler linhas de texto em um arquivo de texto, é preferível utilizar a classe BufferedReader com o seguinte construtor:
BufferedReader(Reader in) | abre um fluxo de leitura com buffer a partir de um fluxo de entrada in. Esse fluxo do tipo Reader pode ser proveniente do teclado, de um arquivo, 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 tamanho) | lê taille caracteres do arquivo e os coloca na matriz buffer a partir da posição offset. |
void close() | fecha o fluxo de leitura |
Aqui está um programa que lê o conteúdo do arquivo criado anteriormente:
// classes importadas
import java.util.*;
import java.io.*;
public class lire{
public static void main(String[] arg){
personne p=null;
// abertura do arquivo
BufferedReader IN=null;
try{
IN=new BufferedReader(new FileReader("out"));
} catch (Exception e){
Erreur(e,1);
}
// dados
String ligne=null;
String[] champs=null;
String prenom=null;
String nom=null;
int age=0;
// gestão de possíveis erros
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));
}// fim do while
} catch (Exception e){
Erreur(e,2);
}
// fechamento do arquivo
try{
IN.close();
} catch (Exception e){
Erreur(e,3);
}
}// fim de main
// Erro
public static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}
}// fim da classe
A execução do programa produz os seguintes resultados:
4.9.3. Salvamento de um objeto “pessoa”
Aplicamos o que acabamos de ver para fornecer à classe personne um método que permita salvar os atributos de uma pessoa em um arquivo. Adicionamos o método sauveAttributs à definição da classe personne:
// ------------------------------
// salvar em arquivo de texto
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
Antes de definir a classe personne, não se esqueça de importar o pacote java.io:
O método sauveAttributs recebe como único parâmetro o fluxo PrintWriter, no qual deve gravar. Um programa de teste poderia ser o seguinte:
// importações
import java.io.*;
// importar pessoa;
public class sauver{
public static void main(String[] arg){
// abertura do arquivo
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// gravação no arquivo
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);
}
// fechamento do arquivo
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// fim da função main
// Erro
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Erro
}//classe
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. Os arquivos binários
4.10.1. A classe RandomAccessFile
A classe RandomAccessFile permite gerenciar arquivos binários, especialmente aqueles com estrutura fixa, como os conhecidos na linguagem C/C++. Aqui estão alguns métodos e construtores úteis:
RandomAccessFile(String nomeDoArquivo, String modo) | construtor — abre o arquivo indicado no modo especificado. Os valores do modo são: r: abertura para leitura rw: abertura para leitura e gravação |
void writeTTT(TTT valor) | grava o valor no arquivo. TTT representa o tipo do valor. A representação em memória do valor é gravada tal como está no arquivo. Assim, encontramos writeBoolean, writeByte, writeInt, writeDouble, writeLong, writeFloat,... Para gravar uma string, utiliza-se writeBytes(String string). |
TTT readTTT() | lê e retorna um valor do tipo TTT. Assim, temos readBoolean, readByte, readInt, readDouble, readLong, readFloat,... O método read() lê um byte. |
long length() | tamanho do arquivo em bytes |
long getFilePointer() | posição atual do ponteiro do arquivo |
void seek(long pos) | posiciona o cursor do arquivo no byte pos |
4.10.2. A classe artigo
Todos os exemplos a seguir utilizarão a seguinte classe article:
// a estrutura do artigo
private static class article{
// define-se a estrutura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//classe do artigo
A classe Java article acima será equivalente à seguinte estrutura article em C
struct article{
char code[4];
char nom[20];
double prix;
int stockActuel;
int stockMinimum;
}//estrutura
Assim, limitaremos o código a 4 caracteres e o nome a 20.
4.10.3. Gravar um registro
O programa a seguir grava um registro em um arquivo chamado “data”:
// classes importadas
import java.io.*;
public class test1{
// testa a gravação de uma estrutura (no sentido do C) em um arquivo binário
// a estrutura do artigo
private static class article{
// define-se a estrutura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//classe artigo
public static void main(String arg[]){
// define-se o arquivo binário no qual os artigos serão armazenados
RandomAccessFile fic=null;
// define-se um artigo
article art=new article();
art.code="a100";
art.nom="velo";
art.prix=1000.80;
art.stockActuel=100;
art.stockMinimum=10;
// define-se o arquivo
try{
fic=new RandomAccessFile("data","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// escreve-se
try{
ecrire(fic,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement",2);
}//try-catch
// pronto
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}//main
// método de escrita
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// código
fic.writeBytes(art.code);
// o nome está limitado a 20 caracteres
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);
// o preço
fic.writeDouble(art.prix);
// estoques
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// fim da gravação
// ------------------------erro
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fim do erro
}// fim da classe
É o programa a seguir que nos permite verificar se a execução ocorreu corretamente.
4.10.4. Ler um registro
// classes importadas
import java.io.*;
public class test2{
// testa a gravação de uma estrutura (no sentido do C) em um arquivo binário
// a estrutura artigo
private static class article{
// definimos a estrutura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//classe artigo
public static void main(String arg[]){
// define-se o arquivo binário no qual os artigos serão armazenados
RandomAccessFile fic=null;
// abre-se o arquivo para leitura
try{
fic=new RandomAccessFile("data","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// lê-se o único artigo do arquivo
article art=new article();
try{
lire(fic,art);
} catch (IOException E){
erreur("Erreur lors de la lecture de l'enregistrement",2);
}//try-catch
// exibimos o registro lido
affiche(art);
// concluído
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}// fim manual
// método de leitura
public static void lire(RandomAccessFile fic, article art) throws IOException{
// leitura do código
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// nome
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// preço
art.prix=fic.readDouble();
// estoques
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fim da gravação
// ---------------------exibir
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);
}// fim da exibição
// ------------------------erro
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fim do erro
}// fim da classe
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
Conseguimos recuperar o registro que havia sido 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 um registro. Agora, gravamos vários registros em um arquivo binário chamado data.bin. Os dados são extraídos do seguinte arquivo 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
// classes importadas
import java.io.*;
import java.util.*;
public class test3{
// arquivo de texto --> arquivo binário
// a estrutura do artigo
private static class article{
// definimos a estrutura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//classe artigo
public static void main(String arg[]){
// define-se o arquivo binário no qual os artigos serão armazenados
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin",1);
}
// os dados são extraídos de um arquivo de texto
BufferedReader dataTxt=null;
try{
dataTxt=new BufferedReader(new FileReader("data.txt"));
} catch (IOException E){
erreur("Impossible d'ouvrir le fichier data.txt",2);
}
// arquivo .txt --> arquivo .bin
String ligne=null;
String[] champs=null;
int numLigne=0;
String champ=null;
article art=new article(); // artigo a ser criado
try{
while((ligne=dataTxt.readLine())!=null){
// uma linha de +
numLigne++;
// divisão em campos
champs=ligne.split(":");
// são necessários 5 campos
if(champs.length!=5)
erreur("Ligne "+numLigne+" erronée dans data.txt",3);
//código
art.code=champs[0];
if(art.code.length()!=4)
erreur("Code erroné en ligne "+numLigne+" du fichier data.txt",12);
// sobrenome, nome
art.nom=champs[1];
// preço
try{
art.prix=Double.parseDouble(champs[2]);
} catch (Exception E){
erreur("Prix erroné en ligne "+numLigne+" du fichier data.txt",4);
}
// estoque atual
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// estoque atual
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// gravamos o registro
try{
ecrire(dataBin,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement "+numLigne,7);
}
// avança para a próxima linha
}// fim do while
} catch (IOException E){
erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
}
// concluído
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);
}
}// fim de main
// método de gravação
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// código
fic.writeBytes(art.code);
// o nome está limitado a 20 caracteres
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);
// o preço
fic.writeDouble(art.prix);
// estoques
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// fim da gravação
// ------------------------erro
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fim do erro
}// fim da classe
Este é o programa que permite verificar se o anterior funcionou corretamente.
4.10.6. Conversão de binário para texto
O programa a seguir lê o conteúdo do arquivo binário data.bin criado anteriormente e grava esse conteúdo no arquivo de texto data.text. Se tudo correr bem, o arquivo data.text deve ser idêntico ao arquivo original data.txt.
// classes importadas
import java.io.*;
import java.util.*;
public class test5{
// arquivo de texto --> arquivo binário
// a estrutura do artigo
private static class article{
// definimos a estrutura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//classe artigo
// função principal
public static void main(String arg[]){
// define-se o arquivo binário no qual os artigos serão armazenados
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// os dados são gravados em um arquivo de texto
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);
}
// arquivo .bin --> arquivo .text
article art=new article(); // artigo a ser criado
// o arquivo binário é processado
int numRecord=0;
long l=0; // tamanho do arquivo
try{
l=dataBin.length();
} catch (IOException e){
erreur("Erreur lors du calcul de la longueur du fichier data.bin",2);
}
long pos=0; // posição atual no arquivo
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
// enquanto não tiver sido ultrapassado o fim do arquivo
while(pos<l){
// ler o registro atual e processá-lo
numRecord++;
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
affiche(art);
// gravação da linha de texto correspondente em dataTxt
dataTxt.println(art.code.trim()+":"+art.nom.trim()+":"+art.prix+":"+art.stockActuel+":"+art.stockMinimum);
// continuamos?
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
}// fim do while
// pronto
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);
}
}// fim de main
// método de leitura
public static void lire(RandomAccessFile fic, article art) throws IOException{
// leitura de código
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// nome
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// preço
art.prix=fic.readDouble();
// estoques
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fim da gravação
// ---------------------exibir
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);
}// fim da exibição
// ------------------------erro
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fim do erro
}// fim da classe
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 registros
Este último programa ilustra a possibilidade de acessar diretamente os registros de um arquivo binário. Ele exibe o registro do arquivo data.bin, cujo número é passado como parâmetro, sendo que o primeiro registro tem o número 1.
// classes importadas
import java.io.*;
import java.util.*;
public class test6{
// arquivo de texto --> arquivo binário
// a estrutura do artigo
private static class article{
// definimos a estrutura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//classe artigo
// função principal
public static void main(String[] args){
// verifica-se os argumentos
int nbArguments=args.length;
String syntaxe="syntaxe : pg numéro_de_fiche";
if(nbArguments!=1)
erreur(syntaxe,20);
// verificação do número do registro
int numRecord=0;
try{
numRecord=Integer.parseInt(args[0]);
} catch(Exception e){
erreur(syntaxe+"\nNuméro de fiche incorrect",21);
}
// abre-se o arquivo binário para leitura
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// navega-se até o registro desejado
try{
dataBin.seek((numRecord-1)*40);
} catch (Exception e){
erreur("La fiche "+numRecord+" n'existe pas",23);
}
// leitura do registro
article art=new article();
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
// exibimos o arquivo
affiche(art);
// pronto
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",2);
}//try-catch
}// fim do main
// método de leitura
public static void lire(RandomAccessFile fic, article art) throws IOException{
// código de leitura
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// nome
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// preço
art.prix=fic.readDouble();
// estoques
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fim da gravação
// ---------------------exibir
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);
}// fim da exibição
// ------------------------erro
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fim do erro
}// fim da classe
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. Usar expressões regulares
4.11.1. O pacote java.util.regex
O pacote java.util.regex permite o uso de expressões regulares. Elas permitem verificar o formato de uma sequência de caracteres. Assim, é possível verificar se uma sequência que representa uma data está, de fato, no formato dd/mm/aa. Para isso, utiliza-se um modelo e compara-se a sequência com esse modelo. Portanto, neste exemplo, j, m e a devem ser números. O modelo de um formato de data válido é, portanto, “\d\d/\d\d/\d\d”, em que o símbolo \d representa um algarismo. Os símbolos que podem ser utilizados em um modelo são os seguintes (documentação da Microsoft):
Caractere | Descrição |
\ | Marca o caractere seguinte como 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 final da entrada. |
* | Corresponde ao caractere anterior zero ou mais vezes. Assim, “zo*” corresponde a “z” ou a “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) | Pesquisa por modèle e armazena a correspondência. A subcadeia correspondente pode ser extraída da coleção Matches obtida, usando Item [0]...[n]. Para encontrar correspondências com caracteres entre parênteses ( ), use "\(" ou "\)". |
x|y | Corresponde tanto a x quanto 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 vezes o caractere. Por exemplo, “o{2}” não corresponde a “o” em “Bob,”, mas aos dois primeiros “o” em “fooooot”. |
{n,} | n é um número inteiro não negativo. Corresponde a pelo menos n vezes o caractere. Por exemplo, “o{2,}” não corresponde ao “o” em “Bob”, mas a todos os “o” em “fooooot”. “o{1,}” equivale a “o+” e “o{0,}” equivale a “o*”. |
{n,m} | m e n são números inteiros não negativos. Corresponde a pelo menos n e, no máximo, m vezes o caractere. Por exemplo, “o{1,3}” corresponde aos três primeiros “o” em “foooooot” e “o{0,1}” equivale a “o?”. |
[xyz] | Conjunto de caracteres. Corresponde a um dos caracteres indicados. Por exemplo, “[abc]” corresponde a “a” em “plat”. |
[^xyz] | Conjunto de caracteres negativo. Corresponde a qualquer caractere não indicado. Por exemplo, “[^abc]” corresponde a “p” em “prato”. |
[a-z] | Intervalo de caracteres. Corresponde a qualquer caractere na série especificada. Por exemplo, “[a-z]” corresponde a qualquer letra minúscula entre “a” e “z”. |
[^m-z] | Intervalo de caracteres negativo. Corresponde a qualquer caractere que não esteja na série especificada. Por exemplo, “[^m-z]” corresponde a qualquer caractere que não esteja entre “m” e “z”. |
\b | Corresponde a um delimitador que representa uma palavra, ou seja, à posição entre uma palavra e um espaço. Por exemplo, “er\b” corresponde a “er” em “lever”, mas não a “er” em “verbe”. |
\B | Corresponde a um delimitador que não representa uma palavra. “en*t\B” corresponde a “ent” em “bien entendu”. |
\d | Corresponde a um caractere que representa um algarismo. É equivalente a [0-9]. |
\D | Corresponde a um caractere que não representa um algarismo. É equivalente a [^0-9]. |
\f | Corresponde a um caractere de quebra de página. |
\n | Corresponde a um caractere de nova linha. |
\r | Corresponde 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 de espaço não em branco. Equivale 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 e inclua um 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 às correspondências armazenadas. Por exemplo, “(.)\1” corresponde a dois caracteres idênticos consecutivos. |
|
Um elemento em um modelo pode aparecer uma ou mais vezes. Vejamos alguns exemplos relacionados ao símbolo \d, que representa um dígito:
modelo | 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 |
Imaginemos agora o modelo capaz de descrever o formato esperado para uma sequência de caracteres:
cadeia procurada | modelo |
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 número inteiro sem sinal | \d+ |
uma sequência de espaços, que pode estar vazia | \s* |
um número inteiro sem sinal que pode ser precedido ou seguido por espaços | \s*\d+\s* |
um número inteiro que pode ser com sinal 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 com sinal e precedido ou seguido por espaços | \s*[+|]?\s*\d+(.\d*)?\s* |
uma sequência de caracteres contendo a palavra “justo” | \bjusto\b |
É possível especificar onde procurar o padrão na sequência:
padrão | significado |
^padrão | o padrão inicia a sequência |
padrão$ | o modelo encerra a sequência |
^padrão$ | o modelo inicia e encerra a sequência |
padrão | o padrão é procurado em toda a sequência, começando pelo início dela. |
sequência pesquisada | padrão |
uma sequência que termina com um ponto de exclamação | !$ |
uma sequência que termina com um ponto | \.$ |
uma sequência que começa com // | ^// |
uma sequência contendo apenas uma palavra, eventualmente seguida ou precedida por espaços | ^\s*\w+\s*$ |
uma sequência contendo duas palavras, eventualmente seguidas ou precedidas por espaços | ^\s*\w+\s*\w+\s*$ |
uma sequência que contenha a palavra “secret” | \bsecret\b |
Os subconjuntos de um padrão podem ser “recuperados”. Assim, não só é possível verificar se uma sequência corresponde a um padrão específico, como também é possível recuperar nessa sequência os elementos correspondentes aos subconjuntos do padrão que foram colocados entre parênteses. Assim, se analisarmos uma sequência que contenha uma data dd/mm/aa e quisermos, além disso, extrair os elementos dd, mm e aa dessa data, utilizaremos o modelo (\d\d)/(\d\d)/(\d\d).
4.11.2. Verificar se uma sequência corresponde a um modelo determinado
A classe Pattern permite verificar se uma string corresponde a um modelo determinado. Para isso, utiliza-se o método estático
com: modèle: o modelo a ser verificado; chaine: a sequência a ser comparada com o modelo. O resultado é o valor booleano true se a sequência corresponder ao modelo; false caso contrário.
Veja um exemplo:
import java.io.*;
import java.util.regex.*;
// gerenciamento de expressões regulares
public class regex1 {
public static void main(String[] args){
// uma expressão regular modelo
String modèle1="^\\s*\\d+\\s*$";
// comparar um exemplo com o modelo
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
}//main
public static void affiche(String msg){
System.out.println(msg);
}//exibe
}//classificar
e os resultados da execução:
Observe que, no padrão "^\s*\d+\s*$", o caractere \ deve ser duplicado devido à interpretação específica que o Java faz desse caractere. Portanto, escreve-se: String padrão1 = "^\\s*\\d+\\s*$";
4.11.3. Encontrar todos os elementos de uma string que correspondam a um padrão
Consideremos o padrão "\d+" e a string " 123 456 789 ". O padrão aparece em três pontos diferentes da string. As classes Pattern e Matcher permitem recuperar as diferentes ocorrências de um padrão em uma string. A classe Pattern é a classe responsável pelas expressões regulares. Uma expressão regular usada mais de uma vez precisa ser “compilada”. Isso acelera as buscas pelo padrão nas cadeias de caracteres. O método estático compile realiza essa tarefa:
Ela recebe como parâmetro a string do padrão e retorna um objeto Pattern. Para comparar o padrão de um objeto Pattern com uma string de caracteres, utiliza-se a classe Matcher. Essa classe permite a comparação de um padrão com uma string de caracteres. A partir de um objeto Pattern, é possível obter um objeto do tipo Matcher com o método matcher:
input é a sequência de caracteres que deve ser comparada ao padrão.
Assim, para comparar o padrão "\d+" com a sequência " 123 456 789 ", é possível criar um objeto Matcher da seguinte maneira:
A partir do objeto résultats anterior, será possível recuperar as diferentes ocorrências do padrão na cadeia. Para isso, utilizam-se os métodos suivantes da classe Matcher:
O método find procura na string analisada a primeira ocorrência do padrão. Uma segunda chamada ao método find procurará a ocorrência seguinte. E assim por diante. O método retorna true se encontrar o padrão; caso contrário, retorna false. A parte da sequência correspondente à última ocorrência encontrada por find é obtida com o método group e sua posição com o método start. Assim, se continuarmos com o exemplo anterior e quisermos exibir todas as ocorrências do padrão "\d+" na sequência " 123 456 789 ", escreveremos:
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 reinicializar o objeto Matcher no início da sequência comparada ao padrão. Assim, o método find encontrará novamente a primeira ocorrência do padrão.
Veja um exemplo completo:
import java.io.*;
import java.util.regex.*;
// gerenciamento de expressões regulares
public class regex2 {
public static void main(String[] args){
// várias ocorrências do padrão na instância
String modèle2="\\d+";
Pattern regex2=Pattern.compile(modèle2);
String exemplaire3=" 123 456 789";
// busca por ocorrências do modelo no exemplar
Matcher matcher2=regex2.matcher(exemplaire3);
while(matcher2.find()){
affiche("séquence " + matcher2.group() + " trouvée en position " + matcher2.start());
}//enquanto
}//Main
public static void affiche(String msg){
System.out.println(msg);
}//exibe
}//classifica
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. Recuperar partes de um modelo
Subconjuntos de um modelo podem ser “recuperados”. Assim, não só é possível verificar se uma sequência corresponde a um modelo específico, como também é possível recuperar nessa sequência os elementos correspondentes aos subconjuntos do modelo que foram colocados entre parênteses. Assim, se analisarmos uma sequência de caracteres contendo uma data dd/mm/aa e quisermos, além disso, extrair os elementos dd, mm e aa dessa data, utilizaremos o modelo (\d\d)/(\d\d)/(\d\d).
Vejamos o seguinte exemplo:
import java.io.*;
import java.util.regex.*;
// gerenciamento de expressões regulares
public class regex3 {
public static void main(String[] args){
// captura de elementos no modelo
String modèle3="(\\d\\d):(\\d\\d):(\\d\\d)";
Pattern regex3=Pattern.compile(modèle3);
String exemplaire4="Il est 18:05:49";
// verificação do modelo
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// a instância corresponde ao modelo
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// exibição dos grupos
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//for
}else{
// o exemplar não corresponde ao modelo
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
}//Página inicial
public static void affiche(String msg){
System.out.println(msg);
}//exibe
}//classifica
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 novidade está na seguinte parte do código:
// verificação do modelo
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// o exemplar corresponde ao modelo
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// exibindo os grupos
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//para
}else{
// o exemplar não corresponde ao modelo
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
A sequência exemplaire4 é comparada ao modelo regex3 por meio do método find. Uma ocorrência do modelo regex3 é então encontrada na sequência exemplaire4. Se o modelo incluir subconjuntos entre parênteses, estes estão disponíveis por meio de diversos métodos da classe Matcher:
public int groupCount()
public String group(int group)
public int start(int group)
O método groupCount fornece o número de subconjuntos encontrados no modelo e group(i) fornece o subconjunto nº i. Este é encontrado na sequência em uma posição determinada 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 localizará a sequência 18:05:49 e criará automaticamente os três subconjuntos definidos pelos parênteses do modelo, respectivamente 18, 05 e 49.
4.11.5. Um programa de treinamento
Encontrar a expressão regular que nos permite verificar se uma string corresponde a um determinado modelo pode, às vezes, ser um verdadeiro desafio. O programa a seguir permite praticar. Ele solicita um modelo e uma string e, em seguida, indica se a string corresponde ou não ao modelo.
import java.io.*;
import java.util.regex.*;
// gerenciamento de expressões regulares
public class regex4 {
public static void main(String[] args){
// dados
String modèle=null,chaine=null;
Pattern regex=null;
BufferedReader IN=null;
Matcher résultats=null;
int nbOccurrences=0;
// gerenciamento de erros
try{
// solicita-se ao usuário os modelos e os exemplares a serem comparados com este
while(true){
// fluxo de entrada
IN=new BufferedReader(new InputStreamReader(System.in));
// solicita-se o modelo
System.out.print("Tapez le modèle à tester ou fin pour arrêter :");
modèle=IN.readLine();
// Concluído?
if(modèle.trim().toLowerCase().equals("fin")) break;
// cria-se a expressão regular
regex=Pattern.compile(modèle);
// solicita-se ao usuário os exemplos a serem comparados com o modelo
while(true){
System.out.print("Tapez la chaîne à comparer au modèle ["+modèle+"] ou fin pour arrêter :");
chaine=IN.readLine();
// concluído?
if(chaine.trim().toLowerCase().equals("fin")) break;
// cria-se o objeto matcher
résultats=regex.matcher(chaine);
// procura-se as ocorrências do modelo
nbOccurrences=0;
while(résultats.find()){
// encontrou-se uma ocorrência
nbOccurrences++;
// ela é exibida
System.out.println("J'ai trouvé la correspondance ["+résultats.group()
+"] en position "+résultats.start());
// exibição dos subelementos
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));
}//para j
}//if
// próxima sequência
}//while(résultats.find())
// foi encontrada pelo menos uma ocorrência?
if(nbOccurrences==0){
System.out.println("Je n'ai pas trouvé de correspondance au modèle ["+modèle+"]");
}//if
// próximo padrão
}//while(true)
}//while(true)
}catch(Exception ex){
// erro
System.err.println("Erreur : "+ex.getMessage());
// fim com erro
System.exit(1);
}//try-catch
// fim
System.exit(0);
}//Main
}//classe
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
Consideremos uma sequência de caracteres composta por campos separados por uma sequência separadora definida por 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 sequência separadora dos campos seria “\s*,\s*”. O método split da classe Pattern nos permite recuperar os campos em um array:
public String[] split(CharSequence input)
A cadeia input é decomposta em campos, separados por um separador que corresponde ao modelo do objeto Pattern atual. Para recuperar os campos de uma linha cujo separador de campos seja a vírgula precedida ou seguida por qualquer número de espaços, escreveremos:
// uma linha
String ligne="abc ,, def , ghi";
// um modelo
Pattern modèle=Pattern.compile("\\s*,\\s*");
// decomposição de linha em campos
String[] champs=modèle.split(ligne);
É possível obter o mesmo resultado com 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.*;
// gerenciamento de expressões regulares
public class split1 {
public static void main(String[] args){
// uma linha
String ligne="abc ,, def , ghi";
// um modelo
Pattern modèle=Pattern.compile("\\s*,\\s*");
// decomposição de linha em campos
String[] champs=modèle.split(ligne);
// exibição
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
// outra maneira de fazer
champs=ligne.split("\\s*,\\s*");
// exibição
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
}//Principal
}//classe
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 costumam ser chamados da seguinte maneira:
$ pg -o1 v1 v2 ... -o2 v3 v4 …
onde -oi representa uma opção e vi um valor associado a essa opção. Deseja-se criar uma classe options que permita analisar a sequência de argumentos -o1 v1 v2 ... -o2 v3 v4 … a fim de construir as seguintes entidades:
optionsValides | 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 |
optionsInvalides | 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 |
optionsSans | cadeia de caracteres (String) que fornece a lista dos valores vi não associados a uma opção |
erreur | número inteiro igual a 0 se não houver erros na linha de argumentos; caso contrário, outro valor: 1: há parâmetros de chamada inválidos 2: há opções inválidas 4: há valores não associados a opções Se houver vários tipos de erros, esses valores são somados. |
Um objeto options pode ser criado de quatro maneiras diferentes:
public options (String arguments, String optionsAcceptables)
arguments | a linha de argumentos -o1 v1 v2 ... -o2 v3 v4 … a ser analisada |
optionsAcceptables | 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, os dois argumentos são cadeias de caracteres. Serão aceitos os casos em que essas cadeias tenham sido divididas em palavras e colocadas em um array de cadeias de caracteres. Isso requer três outros construtores:
public options (String[] arguments, String optionsAcceptables)
public options (String arguments, String[] optionsAcceptables)
public options (String[] arguments, String[] optionsAcceptables)
A classe options apresentará a seguinte interface (acessadores):
retorna a referência da tabela optionsValides criada durante a criação do objeto de opções
retorna a referência da matriz optionsInvalides criada durante a criação do objeto “options”
retorna a referência da cadeia optionsSans criada durante a criação do objeto de opções
retorna o valor do atributo de erro criado durante a criação do objeto de opções
se não houver erro, exibe os valores dos atributos optionsValides, optionsInvalides, optionsSans; caso contrário, exibe o número do erro.
Aqui está um programa de exemplo:
import java.io.*;
//opções de importação;
public class test1{
public static void main (String[] arg){
// abertura do fluxo de entrada
String ligne;
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
affiche(e);
System.exit(1);
}
// leitura dos argumentos do construtor 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));
}// fim do while
}//fim de main
public static void affiche(Exception e){
System.err.println("Erreur : "+e);
}
}//fim da classe
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
Deseja-se criar uma classe stringtovector que permita transferir o conteúdo de um objeto String para um objeto Vector. Essa classe seria derivada da classe Vector:
e teria o seguinte construtor:
private void stringtovector(String S, String separateur, int[] tChampsVoulus,
boolean strict){
// cria um vetor com os campos da string S
// essa é composta por campos separados por separador
// se separador=nulo, a string forma apenas um único campo
// são desejados apenas os campos cujos índices estejam na tabela tChampsVoulus
// são desejados. Os índices começam em 1
// se tChampsvoulus for nulo ou tiver tamanho zero, todos os campos são considerados
// se strict=verdadeiro, todos os campos desejados devem estar presentes
A classe teria o seguinte atributo privado:
Esse atributo é definido pelo construtor anterior com os seguintes valores:
0: a construção ocorreu sem problemas
4: alguns campos solicitados estão ausentes, embora strict=true
A classe também terá dois métodos:
que retorna o valor do atributo privado erreur.
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 ser o seguinte:
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.
- Colocar os campos de S em um dicionário D indexado pelo número do campo
- Recuperar do dicionário D apenas os campos cuja chave (índice) esteja presente na tabela tChampsVoulus.
4.12.3. Exercício 3
Deseja-se adicionar à classe stringtovector o seguinte construtor:
public stringtovector(String S, String separateur, String sChampsVoulus,boolean strict){
// cria um vetor com os campos da string S
// esta é composta por campos separados pelo separador
// se separador=nulo, a string forma apenas um único campo
// somente os campos cujos índices estão em sChampsVoulus são desejados
// os índices começam em 1
// se sChampsvoulus for nulo ou "", todos os campos são selecionados
// se strict=verdadeiro, todos os campos desejados devem estar presentes
A lista dos campos desejados está, portanto, em uma string (String) em vez de uma matriz de inteiros (int[]). O atributo privado erreur da classe pode receber um novo valor:
2: a sequência de í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:
- É preciso seguir o exemplo do construtor anterior, transferindo os campos da string sChampsVoulus para uma matriz de inteiros. Para isso, divida sChampsVoulus em campos usando um objeto StringTokenizer, cujo atributo countTokens indicará o número de campos obtidos. Em seguida, é possível criar uma matriz de inteiros com o tamanho adequado e preenchê-la com os campos obtidos.
- Para verificar se um campo é inteiro, utilize o método Integer.parseInt para converter o campo em inteiro e lide com a exceção que será gerada caso essa conversão seja impossível.
4.12.4. Exercício 4
Deseja-se criar uma classe filetovector que permita transferir o conteúdo de um arquivo de texto para um objeto *Vector. Essa classe seria derivada da classe *Vector:
e teria o seguinte construtor:
// --------------------- construtor
public filetovector(String nomFichier, String separateur, int [] tChampsVoulus,boolean strict, String tagCommentaire){
// cria um vetor com as linhas do arquivo de texto nomFichier
// as linhas são compostas por campos separados por separador
// se separador=nulo, a linha forma apenas um único campo
// só são desejados os campos cujos índices estejam em tChampsVoulus
// os índices começam em 1
// se tChampsvoulus for nulo ou vazio, todos os campos são incluídos
// se strict=verdadeiro, todos os campos desejados devem estar presentes
// caso contrário, a linha não é armazenada e seu índice
// é colocado no vetor lignesErronees
// as linhas em branco são ignoradas
// assim como as linhas que começam com tagCommentaire, se tagCommentaire != null
A classe teria os seguintes atributos privados:
O atributo erreur é definido pelo construtor anterior com os seguintes valores:
0: a construção ocorreu sem problemas
1: não foi possível abrir o arquivo a ser processado
4: alguns campos solicitados estão ausentes, embora strict=true
8: ocorreu um erro de E/S durante a processamento do arquivo
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 com erro se não puder fornecer os campos solicitados, embora strict=true.
A classe também terá dois métodos:
que retorna o valor do atributo privado erreur.
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 arquivo 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,# comentário) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# comentário) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Algumas dicas
-
O arquivo de texto é processado linha por linha. A linha é dividida em campos por meio da classe
**stringtovector,** estudada anteriormente. -
Os elementos do vetor criado a partir do arquivo de texto são, portanto, objetos do tipo stringtovector.
-
O método identite de filetovector poderá utilizar o método stringtovector.identite() para exibir seus elementos, bem como o método Vector.toString() para exibir os números das eventuais linhas com erros.
4.12.5. Exercício 5
Deseja-se adicionar à classe **filetovector** o seguinte construtor:
public filetovector(String nomFichier, String separateur, String sChampsVoulus,
boolean strict, String tagCommentaire){
// cria um vetor com as linhas do arquivo de texto nomFichier
// as linhas são compostas por campos separados por separador
// se separador=nulo, a linha forma apenas um único campo
// só são desejados os campos cujos índices estejam em tChampsVoulus
// os índices começam em 1
// se sChampsvoulus for nulo ou vazio, todos os campos são selecionados
// se strict=verdadeiro, todos os campos desejados devem estar presentes
// caso contrário, a linha não é armazenada e seu índice
// é colocado no vetor lignesErronees
// as linhas em branco são ignoradas
// assim como as linhas que começam com tagCommentaire, se tagCommentaire != null
A lista de índices dos campos desejados agora está em uma cadeia de caracteres (String), em vez de estar em uma matriz de inteiros.
O atributo privado erreur pode ter um valor adicional:
2: a sequência de índices dos campos desejados 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());
}
}
Os resultados:
[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,# comentário) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# comentário) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Algumas dicas
- Vamos transformar a sequência sChampsVoulus em uma tabela de inteiros tChampVoulus para nos aproximarmos do caso do construtor anterior.