4. Clases de uso habitual
En este capítulo presentamos una serie de clases de Java de uso habitual. Estas cuentan con numerosos atributos, métodos y constructores. En cada caso, solo presentamos una pequeña parte de las clases. Los detalles de las mismas están disponibles en la ayuda de Java que presentamos a continuación.
4.1. La documentación
Si ha instalado el JDK de Sun en la carpeta <jdk>, la documentación está disponible en la carpeta <jdk>\docs:

A veces se dispone de un archivo jdk, pero sin documentación. Esta se puede encontrar en la página web de Sun: http://www.sun.com. En la carpeta docs hay un archivo index.html que es el punto de partida de la ayuda del JDK:


El enlace API & Language anterior da acceso a las clases de Java. El enlace Demos/Tutorials resulta especialmente útil para consultar ejemplos de programas en Java. Sigamos el enlace API & Language:

Sigamos el enlace «Java 2 Platform» API:

Esta página es el verdadero punto de partida de la documentación sobre las clases. Se puede crear un acceso directo a ella para acceder rápidamente. El URL se encuentra en <jdk>\docs\api\index.html. En ella se encuentran enlaces a los cientos de clases Java del JDK. Cuando se empieza, la principal dificultad es saber qué hacen estas diferentes clases. Por lo tanto, en un primer momento, esta ayuda solo resulta útil si se conoce el nombre de la clase sobre la que se desea obtener información. También se puede seguir la pista de los nombres de las clases, que normalmente indican la función de la clase.
Veamos un ejemplo y busquemos información sobre la clase Vector, que implementa una matriz dinámica. Basta con buscar en la lista de clases del panel de la izquierda el enlace de la clase Vector:

y hacer clic en el enlace para ver la definición de la clase:

Allí se encuentra
- la jerarquía en la que se encuentra la clase, en este caso java.util.Vector
- la lista de campos (atributos) de la clase
- la lista de constructores
- la lista de métodos
A continuación, presentamos diversas clases. Invitamos al lector a que compruebe sistemáticamente la definición completa de las clases utilizadas.
4.2. Las clases de prueba
Los ejemplos que siguen utilizan en ocasiones las clases personne y enseignant. A continuación recordamos su definición.
public class personne{
// apellidos, nombre, edad
private String prenom;
private String nom;
private int age;
// constructor 1
public personne(String P, String N, int age){
this.prenom=P;
this.nom=N;
this.age=age;
}
// constructor 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+")";
}
// accesorios
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;
}
}
La clase enseignant se deriva de la clase personne y se define de la siguiente manera:
class enseignant extends personne{
// atributos
private int section;
// constructor
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+")";
}
}
También utilizaremos una clase etudiant derivada de la clase personne y definida de la siguiente manera:
class etudiant extends personne{
String numero;
public etudiant(String P, String N, int age,String numero){
super(P,N,age);
this.numero=numero;
}
public String toString(){
return "etudiant("+super.toString()+","+numero+")";
}
}
4.3. La clase String
La clase String representa las cadenas de caracteres. Supongamos que nom es una variable de cadena de caracteres:
String nombre;
nom es una referencia a un objeto aún no inicializado. Se puede inicializar de dos maneras:
nombre = «caballo» o nombre = new String(«caballo»)
Ambos métodos son equivalentes. Si más adelante escribimos nombre="pez", nom pasará a hacer referencia a un nuevo objeto. El objeto anterior, *String("cheval"),* se pierde y se recuperará el espacio de memoria que ocupaba.
La clase String cuenta con numerosos atributos y métodos. Estos son algunos de ellos:
public char charAt(int i) | devuelve el carácter i de la cadena, siendo el primer carácter el que tiene el índice 0. Así, String("caballo").charAt(3) es igual a 'v' |
public int compareTo(cadena2) | chaine1.compareTo(cadena2) compara cadena1 con cadena2 y devuelve 0 si cadena1 = cadena2, 1 si cadena1 > cadena2 y -1 si cadena1 < cadena2 |
public boolean equals(Object anObject) | chaine1.equals(cadena2) devuelve «verdadero» si cadena1 = cadena2, «falso» en caso contrario |
public String toLowerCase() | chaine1.toLowerCase() convierte cadena1 a minúsculas |
public String toUpperCase() | chaine1.toUpperCase() convierte cadena1 a mayúsculas |
public String trim() | chaine1.trim() elimina los espacios iniciales y finales de cadena1 |
public String substring(int beginIndex, int endIndex) | String("chapeau").subString(2,4) devuelve la cadena «ape» |
public char[] toCharArray() | permite colocar los caracteres de la cadena en una matriz de caracteres |
int length() | número de caracteres de la cadena |
int indexOf(String cadena2) | devuelve la primera posición de chaine2 en la cadena actual o -1 si chaine2 no está presente |
int indexOf(String cadena2, int startIndex) | devuelve la primera posición de chaine2 en la cadena actual o -1 si chaine2 no está presente. La búsqueda comienza a partir del carácter n.º startIndex. |
int lastIndexOf(String cadena2) | devuelve la última posición de chaine2 en la cadena actual o -1 si chaine2 no está presente |
boolean startsWith(String cadena2) | devuelve «verdadero» si la cadena actual comienza por chaine2 |
boolean endsWith(String cadena2) | devuelve «verdadero» si la cadena actual termina en chaine2 |
boolean matches(String regex) | devuelve «verdadero» si la cadena actual coincide con la expresión regular regex. |
String[] split(String regex) | La cadena actual está compuesta por campos separados por una cadena de caracteres modelada por la expresión regular regex. El método split permite recuperar los campos en un array. |
String replace(char oldChar, char newChar) | sustituye en la cadena actual el carácter oldChar por el carácter newChar. |
A continuación se muestra un programa de ejemplo:
// importaciones
import java.io.*;
public class string1{
// una clase de demostración
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
// muestra
public static void affiche(String msg){
// muestra msg
System.out.println(msg);
}//muestra
}//clase
y los resultados obtenidos:
uneChaine=l'oiseau vole au-dessus des nuages
uneChaine.Length=34
chaine[10]=o
uneChaine.IndexOf("vole")=9
uneChaine.IndexOf("x")=-1
uneChaine.LastIndexOf('a')=30
uneChaine.LastIndexOf('x')=-1
uneChaine.substring(4,7)=sea
uneChaine.ToUpper()=L'OISEAU VOLE AU-DESSUS DES NUAGES
uneChaine.ToLower()=l'oiseau vole au-dessus des nuages
uneChaine.Replace('a','A')=l'oiseAu vole Au-dessus des nuAges
champs[0]=[l'oiseau]
champs[1]=[vole]
champs[2]=[au-dessus]
champs[3]=[des]
champs[4]=[nuages]
(" abc ").trim()=[abc]
4.4. La clase Vector
Un vector es un array dinámico cuyos elementos son referencias a objetos. Se trata, por tanto, de un array de objetos cuyo tamaño puede variar con el tiempo, algo que no es posible con los arrays estáticos que hemos visto hasta ahora. A continuación se muestran algunos campos, constructores y métodos de esta clase:
public Vector() | crea un vector vacío |
public final int size() | número de elementos del vector |
public final void addElement(Object obj) | añade el objeto al que hace referencia obj al vector |
public final Object elementAt(int índice) | referencia al objeto n.º index del vector; los índices comienzan en 0 |
public final Enumeration elements() | el conjunto de elementos del vector en forma de enumeración |
public final Object firstElement() | referencia al primer elemento del vector |
public final Object lastElement() | referencia al último elemento del vector |
public final boolean isEmpty() | devuelve «true» si el vector está vacío |
public final void removeElementAt(int índice) | elimina el elemento con índice index |
public final void removeAllElements() | vacía el vector de todos sus elementos |
public final String toString() | devuelve una cadena de identificación del vector |
Aquí tienes un programa de prueba:
// las clases importadas
import java.util.*;
public class test1{
// el programa principal main - estático - método de clase
public static void main(String arg[]){
// creación de objetos (instancias de clases)
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());
// el polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// un 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());
}
} // fin de main
}// fin de la clase
Compilemos 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
Ejecutemos el archivo 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 ahora, ya no repetiremos el proceso de compilación y ejecución de los programas de prueba. Basta con seguir los pasos descritos anteriormente.
4.5. La clase ArrayList
La clase ArrayList es análoga a la clase Vector. Solo difiere de ella de manera significativa cuando es utilizada simultáneamente por varios hilos de ejecución. Los métodos de sincronización de subprocesos para acceder a un Vector o a un ArrayList son diferentes. Aparte de este caso, se puede utilizar indistintamente uno u otro. A continuación se muestran algunos campos, constructores o métodos de esta clase:
ArrayList() | crea una lista vacía |
int size() | número de elementos de la lista |
void add(Object obj) | añade el objeto al que hace referencia obj a la lista |
void add(int índice, Object obj) | añade el objeto al que hace referencia obj a la matriz en la posición index |
Object get(int index) | referencia del objeto n.º index de la tabla —los índices comienzan en 0 |
boolean isEmpty() | devuelve «verdadero» si la matriz está vacía |
void remove(int index) | elimina el elemento con índice index |
void clear() | vacía el array de todos sus elementos |
Object[] toArray() | convierte el array dinámico en un array clásico |
String toString() | devuelve una cadena de identificación del array |
Aquí tienes un programa de prueba:
// las clases importadas
import java.util.*;
public class test1{
// el programa principal main - estático - método de clase
public static void main(String arg[]){
// creación de objetos (instancias de clases)
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);
// el polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2);
personne p3=(personne)et;
System.out.println("p3="+p3);
// un 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);
}
} // fin de main
}// fin de la clase
Los resultados obtenidos son los mismos que los anteriores.
4.6. La clase Arrays
La clase java.util.Arrays permite acceder a métodos estáticos que facilitan diversas operaciones con matrices, en particular la ordenación y la búsqueda de elementos. A continuación se muestran algunos de estos métodos:
static void sort(matriz) | ordena tableau utilizando para ello el orden implícito del tipo de datos del array, ya sean números o cadenas de caracteres. |
static void sort (Object[] matriz, Comparator C) | ordena tableau utilizando la función de comparación C para comparar los elementos |
static int binarySearch(matriz, elemento) | devuelve la posición de élément en tableau o un valor <0 en caso contrario. La matriz debe estar ordenada previamente. |
static int binarySearch(Object[] matriz, Object elemento, Comparator C) | Lo mismo, pero utiliza la función de comparación C para comparar dos elementos de la matriz. |
He aquí un primer ejemplo:
import java.util.*;
public class sort2 implements Comparator{
// una clase privada interna
private class personne{
private String nom;
private int age;
public personne(String nom, int age){
this.nom=nom; // nombre de la persona
this.age=age; // su edad
}
// obtener la edad
public int getAge(){
return age;
}
// identidad de la persona
public String toString(){
return ("["+nom+","+age+"]");
}
}; // clase «persona»
// fabricante
public sort2() {
// una tabla de personas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// ordenación de la tabla de personas
Arrays.sort(amis,this);
// verificación
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//creador
// la función que compara personas
public int compare(Object o1, Object o2){
// debe devolver
// -1 si o1 es «menor que» o2
// 0 si o1 «es igual a» o2
// +1 si o1 es «mayor 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
// función de prueba
public static void main(String[] arg){
new sort2();
}//mano
}//clase
Analicemos este programa. La función main crea un objeto *sort2*. El constructor de la clase *sort2* es el siguiente:
// constructor
public sort2() {
// una tabla de personas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// ordenación de la tabla de personas
Arrays.sort(amis,this);
// verificación
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//creador
La matriz que se va a ordenar es una matriz de objetos personne. La clase personne está definida de forma privada (private) dentro de la clase sort2. El método estático sort de la clase Arrays no sabe cómo ordenar un array de objetos personne, por lo que aquí nos vemos obligados a utilizar la forma void sort(Object[] obj, Comparator C). Comparator es una interfaz que solo define un método:
y que debe devolver 0: si o1 = o2, -1: si o1 < o2, +1: si o1 > o2. En el prototipo void sort(Object[] obj, Comparator C), el segundo argumento C debe ser un objeto que implemente la interfaz Comparator. En el constructor sort2, se ha elegido el objeto actual this:
Esto nos obliga a hacer dos cosas:
- indicar que la clase sort2 implementa la interfaz Comparator
- Escribir la función compare en la clase sort2.
Esta es la siguiente:
// la función que compara personas
public int compare(Object o1, Object o2){
// debe devolver
// -1 si o1 es «menor que» o2
// 0 si o1 es «igual a» o2
// +1 si o1 es «mayor 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 dos objetos personne, aquí se utiliza la edad (también se podría haber utilizado el nombre).
Los resultados de la ejecución son los siguientes:
Se podría haber procedido de otra forma para implementar la interfaz Comparator:
import java.util.*;
public class sort2 {
// una clase privada interna
private class personne{
…….
}; // clase persona
// constructor
public sort2() {
// un array de personas
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// ordenación del array de personas
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compara
}//clase
);
// verificación
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//generador
// la función que compara personas
public int compare1(Object o1, Object o2){
// debe devolver
// -1 si o1 es «menor que» o2
// 0 si o1 «es igual a» o2
// +1 si o1 es «mayor 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
}//clase
La instrucción de ordenación ha quedado así:
// ordenación de la tabla de personas
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//comparar
}//clase
);
El segundo parámetro del método sort debe ser un objeto que implemente la interfaz Comparator. Aquí creamos dicho objeto mediante new java.util.Comparator(), y el texto que sigue a {…} define la clase de la que se crea un objeto. A esto se le denomina clase anónima, ya que no tiene nombre. En esta clase anónima, que debe implementar la interfaz Comparator, se define el método compare de dicha interfaz. Este método se limita a llamar al método compare1 de la clase sort2. Así pues, volvemos al caso anterior.
La clase sort2 ya no implementa la interfaz Comparator. Por lo tanto, su declaración queda así:
Ahora probamos el método binarySearch de la clase Arrays con el siguiente ejemplo:
import java.util.*;
public class sort4 {
// una clase privada interna
private class personne{
// atributos
private String nom;
private int age;
// constructor
public personne(String nom, int age){
this.nom=nom; // nombre de la persona
this.age=age; // su edad
}
// obtener el nombre
public String getNom(){
return nom;
}
// obtener la edad
public int getAge(){
return age;
}
// identidad de la persona
public String toString(){
return ("["+nom+","+age+"]");
}
}; // clase de persona
// creador
public sort4() {
// una tabla de personas
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
}//clase
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//compara
}//clasifica
;
// ordenación de la tabla de personas
Arrays.sort(amis,comparateur1);
// verificación
for(int i=0;i<3;i++)
System.out.println(amis[i]);
// búsquedas
cherche("milou",amis,comparateur2);
cherche("xx",amis,comparateur2);
}//generador
// la función que compara personas
public int compare1(Object o1, Object o2){
// debe devolver
// -1 si o1 es «menor que» o2
// 0 si o1 «es igual a» o2
// +1 si o1 es «mayor 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
// la función que compara a una persona con un nombre
public int compare2(Object o1, Object o2){
// o1 es una persona
// o2 es una cadena, el nombre «nombre2» de una persona
// debe devolver
// -1 si o1.nom es «menor que» nom2
// 0 si o1.nom es «igual a» nom2
// +1 si o1.nom es «mayor que» nombre2
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){
// busca a un amigo en la tabla 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");
}//busca
// mano
public static void main(String[] arg){
new sort4();
}//mano
}//clase
En este caso, hemos procedido de forma ligeramente diferente a los ejemplos anteriores. Se han creado los dos objetos Comparator necesarios para los métodos sort y binarySearch, y se han asignado a las variables comparateur1 y comparateur2.
// comparadores
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//compara
}//clase
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//comparar
}//clase
;
En el generador de sort4 se realiza dos veces una búsqueda dicotómica en la tabla amis:
El método cherche recibe todos los parámetros que necesita para llamar al método binarySearch:
public void cherche(String ami,personne[] amis, Comparator comparateur){
// buscar amigo en la tabla 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");
}//busca
El método binarySearch funciona con el comparador comparateur2, que a su vez recurre al método compare2 de la clase sort4. El método rend devuelve la posición del nombre buscado en la tabla si existe, o un número <0 en caso contrario. El método compare2 sirve para comparar un objeto personne con un nombre de tipo String.
// la función que compara a una persona con un nombre
public int compare2(Object o1, Object o2){
// o1 es una persona
// o2 es una cadena, el nombre «nombre2» de una persona
// debe devolver
// -1 si o1.nom «es menor que» nombre2
// 0 si o1.nom «es igual a» nombre2
// +1 si o1.nom «mayor que» nombre2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//compara2
A diferencia del método sort, el método binarySearch no recibe dos objetos personne, sino un objeto personne y un objeto String en ese orden. El primer parámetro es un elemento de la matriz amis; el segundo, el nombre de la persona buscada.
4.7. La clase Enumeration
Enumeration es una interfaz y no una clase. Tiene los siguientes métodos:
public abstract boolean hasMoreElements() | devuelve «true» si la enumeración aún tiene elementos |
public abstract Object nextElement() | devuelve la referencia al siguiente elemento de la enumeración |
¿Cómo se utiliza una enumeración? Por lo general, así:
Enumeration e=… // se obtiene un objeto de enumeración
while(e.hasMoreElements()){
// se procesa el elemento e.nextElement()
}
He aquí un ejemplo:
// las clases importadas
import java.util.*;
public class test1{
// el programa principal main - estático - método de clase
public static void main(String arg[]){
// creación de objetos (instancias de clases)
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());
// el polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// un 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());
}
// una enumeración
Enumeration E=V.elements();
i=0;
while(E.hasMoreElements()){
p2=(personne) E.nextElement();
System.out.println("V["+i+"]="+p2.toString());
i++;
}
}// fin de main
}//fin de clase
Se obtienen los siguientes 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. La clase Hashtable
La clase Hashtable permite implementar un diccionario. Podemos considerar un diccionario como una tabla de dos columnas:
clave | valor |
clave1 | valor1 |
clave2 | valor2 |
.. | ... |
Las claves son únicas, c.a.d, por lo que no puede haber dos claves idénticas. Los principales métodos y propiedades de la clase Hashtable son los siguientes:
public Hashtable() | constructor: crea un diccionario vacío |
public int size() | número de elementos del diccionario; un elemento es un par (clave, valor) |
public Object put(Object key, Object value) | añade el par (clave, valor) al diccionario |
public Object get(Object key) | recupera el objeto asociado a la clave key o null si la clave key no existe |
public boolean containsKey(Object key) | verdadero si la clave key existe en el diccionario |
public boolean contains(Object value) | verdadero si el valor value existe en el diccionario |
public Enumeration keys() | devuelve las claves del diccionario en forma de enumeración |
public Object remove(Object key) | elimina el par (clave, valor) donde clave = key |
public String toString() | identifica el diccionario |
He aquí un ejemplo:
// las clases importadas
import java.util.*;
public class test1{
// el programa principal main - estático - método de clase
public static void main(String arg[]){
// creación de objetos (instancias de clases)
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());
// el polimorfismo
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// un diccionario
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++;
}
}//fin de main
}//fin de clase
Los resultados obtenidos son los siguientes:
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. Los archivos de texto
4.9.1. Escribir
Para escribir en un archivo, es necesario disponer de un flujo de escritura. Para ello, se puede utilizar la clase FileWriter. Los constructores que se utilizan con más frecuencia son los siguientes:
FileWriter(String fileName) | crea el archivo con el nombre fileName; a continuación, se puede escribir en él; si ya existe un archivo con el mismo nombre, se sobrescribe |
FileWriter(String fileName, boolean append) | lo mismo; si ya existe un archivo con el mismo nombre, se puede utilizar abriéndolo en modo de adición (append=true) |
La clase FileWriter ofrece varios métodos para escribir en un archivo, métodos heredados de la clase Writer. Para escribir en un archivo de texto, es preferible utilizar la clase PrintWriter, cuyos constructores más utilizados son los siguientes:
PrintWriter(Writer out) | El argumento es de tipo Writer o c.a.d. Un flujo de escritura (en un archivo, en la red, etc.). |
PrintWriter(Writer out, boolean autoflush) | Lo mismo. El segundo argumento gestiona el almacenamiento en búfer de las líneas. Cuando es falso (su valor por defecto), las líneas escritas en el archivo pasan por un búfer en memoria. Cuando este se llena, se escribe en el archivo. Esto mejora el acceso al disco. Dicho esto, a veces este comportamiento no es deseable, especialmente cuando se escribe en la red. |
Los métodos útiles de la clase PrintWriter son los siguientes:
void print(Type T) | escribe el dato T (String, int, …) |
void println(Type T) | lo mismo, pero terminando con un carácter de fin de línea |
void flush() | vacía el búfer si no se está en modo autoflush |
void close() | cierra el flujo de escritura |
Aquí tienes un programa que escribe unas cuantas líneas en un archivo de texto:
// importaciones
import java.io.*;
public class ecrire{
public static void main(String[] arg){
// apertura del archivo
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// escritura en el archivo
try{
fic.println("Jean,Dupont,27");
fic.println("Pauline,Garcia,24");
fic.println("Gilles,Dumond,56");
} catch (Exception e){
Erreur(e,3);
}
// cierre del archivo
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// fin de main
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Error
}//clase
El archivo out obtenido tras la ejecución es el siguiente:
4.9.2. Leer
Para leer el contenido de un archivo, es necesario disponer de un flujo de lectura asociado al archivo. Para ello, se puede utilizar la clase FileReader y el siguiente constructor:
FileReader(String nombreArchivo) | abre un flujo de lectura a partir del archivo indicado. Lanza una excepción si la operación falla. |
La clase FileReader dispone de varios métodos para leer un archivo, métodos heredados de la clase Reader. Para leer líneas de texto de un archivo de texto, es preferible utilizar la clase BufferedReader con el siguiente constructor:
BufferedReader(Reader in) | abre un flujo de lectura con búfer a partir de un flujo de entrada in. Este flujo de tipo Reader puede proceder del teclado, de un archivo, de la red, etc. |
Los métodos útiles de la clase BufferedReader son los siguientes:
int read() | lee un carácter |
String readLine() | lee una línea de texto |
int read(char[] buffer, int offset, int tamaño) | lee taille caracteres del archivo y los coloca en el array buffer a partir de la posición offset. |
void close() | cierra el flujo de lectura |
A continuación se muestra un programa que lee el contenido del archivo creado anteriormente:
// clases importadas
import java.util.*;
import java.io.*;
public class lire{
public static void main(String[] arg){
personne p=null;
// apertura del archivo
BufferedReader IN=null;
try{
IN=new BufferedReader(new FileReader("out"));
} catch (Exception e){
Erreur(e,1);
}
// datos
String ligne=null;
String[] champs=null;
String prenom=null;
String nom=null;
int age=0;
// gestión de posibles errores
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));
}// fin del bucle «while»
} catch (Exception e){
Erreur(e,2);
}
// cierre del archivo
try{
IN.close();
} catch (Exception e){
Erreur(e,3);
}
}// fin de «main»
// Error
public static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}
}// fin de clase
Al ejecutar el programa se obtienen los siguientes resultados:
4.9.3. Guardar un objeto «persona»
Aplicamos lo que acabamos de ver para dotar a la clase personne de un método que permita guardar en un archivo los atributos de una persona. Añadimos el método sauveAttributs a la definición de la clase personne:
// ------------------------------
// guardar en archivo de texto
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
Antes de definir la clase personne, no hay que olvidar importar el paquete java.io:
El método sauveAttributs recibe como único parámetro el flujo PrintWriter en el que debe escribir. Un programa de prueba podría ser el siguiente:
// importaciones
import java.io.*;
// importar persona;
public class sauver{
public static void main(String[] arg){
// apertura del archivo
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// escritura en el archivo
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);
}
// cierre del archivo
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// fin de main
// Error
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Error
}//clase
Compilemos y ejecutemos 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. Los archivos binarios
4.10.1. La clase RandomAccessFile
La clase RandomAccessFile permite gestionar archivos binarios, en particular aquellos con estructura fija, como los que se conocen en los lenguajes C/C++. A continuación se muestran algunos métodos y constructores útiles:
RandomAccessFile(String nombreArchivo, String modo) | constructor: abre el archivo indicado en el modo especificado. Este modo puede adoptar los siguientes valores: r: apertura en lectura rw: apertura en lectura y escritura |
void writeTTT(TTT valor) | escribe valor en el archivo. TTT representa el tipo de valor. La representación en memoria de valor se escribe tal cual en el archivo. Así, encontramos writeBoolean, writeByte, writeInt, writeDouble, writeLong, writeFloat, ... Para escribir una cadena, se utiliza writeBytes(String cadena). |
TTT readTTT() | lee y devuelve un valor de tipo TTT. Así, encontramos readBoolean, readByte, readInt, readDouble, readLong, readFloat, ... El método read() lee un byte. |
long length() | tamaño del archivo en bytes |
long getFilePointer() | posición actual del puntero de archivo |
void seek(long pos) | sitúa el cursor del archivo en el byte pos |
4.10.2. La clase «article»
Todos los ejemplos que siguen utilizarán la siguiente clase article:
// la estructura del artículo
private static class article{
// se define la estructura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//clase de artículo
La clase Java article anterior será equivalente a la siguiente estructura article en C
struct article{
char code[4];
char nom[20];
double prix;
int stockActuel;
int stockMinimum;
}//estructura
De este modo, limitaremos el código a 4 caracteres y el nombre a 20.
4.10.3. Escribir un registro
El siguiente programa escribe un artículo en un archivo llamado «data»:
// clases importadas
import java.io.*;
public class test1{
// comprueba la escritura de una estructura (en el sentido del lenguaje C) en un archivo binario
// la estructura del artículo
private static class article{
// se define la estructura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//clase «artículo»
public static void main(String arg[]){
// se define el archivo binario en el que se almacenarán los artículos
RandomAccessFile fic=null;
// se define un artículo
article art=new article();
art.code="a100";
art.nom="velo";
art.prix=1000.80;
art.stockActuel=100;
art.stockMinimum=10;
// se define el archivo
try{
fic=new RandomAccessFile("data","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// se escribe
try{
ecrire(fic,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement",2);
}//try-catch
// ya está
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}//main
// método de escritura
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// código
fic.writeBytes(art.code);
// el nombre 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);
// el precio
fic.writeDouble(art.prix);
// las existencias
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// fin de escritura
// ------------------------error
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fin del error
}// fin de clase
El siguiente programa nos permite comprobar que la ejecución se ha realizado correctamente.
4.10.4. Leer un registro
// clases importadas
import java.io.*;
public class test2{
// comprueba la escritura de una estructura (en el sentido de C) en un archivo binario
// la estructura «article»
private static class article{
// se define la estructura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//clase «artículo»
public static void main(String arg[]){
// se define el archivo binario en el que se almacenarán los artículos
RandomAccessFile fic=null;
// se abre el archivo en modo de lectura
try{
fic=new RandomAccessFile("data","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// se lee el único artículo del archivo
article art=new article();
try{
lire(fic,art);
} catch (IOException E){
erreur("Erreur lors de la lecture de l'enregistrement",2);
}//try-catch
// se muestra el registro leído
affiche(art);
// Se ha completado
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}// fin manual
// método de lectura
public static void lire(RandomAccessFile fic, article art) throws IOException{
// lectura del código
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// nombre
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// precio
art.prix=fic.readDouble();
// stocks
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fin de escritura
// ---------------------visualizar
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);
}// fin de visualización
// ------------------------error
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fin del error
}// fin de clase
Los resultados de la ejecución son los siguientes:
E:\data\serge\JAVA\random>java test2
code : a100
nom : velo
prix : 1000.8
Stock actuel : 100
Stock minimum : 10
Se recupera correctamente el registro que había sido escrito por el programa de escritura.
4.10.5. Conversión de texto a binario
El siguiente programa es una ampliación del programa de escritura de un registro. Ahora escribimos varios registros en un archivo binario llamado data.bin. Los datos se extraen del siguiente archivo 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
// clases importadas
import java.io.*;
import java.util.*;
public class test3{
// archivo de texto --> archivo binario
// la estructura del artículo
private static class article{
// se define la estructura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//clase «artículo»
public static void main(String arg[]){
// se define el archivo binario en el que se almacenarán los artículos
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin",1);
}
// los datos se extraen de un archivo 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);
}
// archivo .txt --> archivo .bin
String ligne=null;
String[] champs=null;
int numLigne=0;
String champ=null;
article art=new article(); // artículo que se va a crear
try{
while((ligne=dataTxt.readLine())!=null){
// una línea de +
numLigne++;
// desglose en campos
champs=ligne.split(":");
// se necesitan 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);
// apellidos, nombre
art.nom=champs[1];
// precio
try{
art.prix=Double.parseDouble(champs[2]);
} catch (Exception E){
erreur("Prix erroné en ligne "+numLigne+" du fichier data.txt",4);
}
// stock actual
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// stock actual
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// se escribe el registro
try{
ecrire(dataBin,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement "+numLigne,7);
}
// se pasa a la línea siguiente
}// fin del bucle «while»
} catch (IOException E){
erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
}
// se ha terminado
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);
}
}// fin de main
// método de escritura
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// código
fic.writeBytes(art.code);
// el nombre 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);
// el precio
fic.writeDouble(art.prix);
// las existencias
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// fin de escritura
// ------------------------error
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fin del error
}// fin de clase
El siguiente programa permite comprobar que este ha funcionado correctamente.
4.10.6. Conversión de binario a texto
El siguiente programa lee el contenido del archivo binario data.bin creado anteriormente y guarda su contenido en el archivo de texto data.text. Si todo va bien, el archivo data.text debería ser idéntico al archivo original data.txt.
// clases importadas
import java.io.*;
import java.util.*;
public class test5{
// archivo de texto --> archivo binario
// la estructura del artículo
private static class article{
// se define la estructura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//clase «artículo»
// función principal
public static void main(String arg[]){
// se define el archivo binario en el que se almacenarán los artículos
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// los datos se escriben en un archivo 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);
}
// archivo .bin --> archivo .text
article art=new article(); // artículo que se va a crear
// se procesa el archivo binario
int numRecord=0;
long l=0; // tamaño del archivo
try{
l=dataBin.length();
} catch (IOException e){
erreur("Erreur lors du calcul de la longueur du fichier data.bin",2);
}
long pos=0; // posición actual en el archivo
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
// mientras no se haya superado el final del archivo
while(pos<l){
// leer el registro actual y procesarlo
numRecord++;
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
affiche(art);
// escribir la línea de texto correspondiente en 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);
}
}// fin del bucle «while»
// ya está
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);
}
}// fin de main
// método de lectura
public static void lire(RandomAccessFile fic, article art) throws IOException{
// lectura de código
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// nombre
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// precio
art.prix=fic.readDouble();
// stocks
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fin de escritura
// ---------------------visualización
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);
}// fin de visualización
// ------------------------error
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fin del error
}// fin de clase
A continuación se muestra un ejemplo de ejecución:
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. Acceso directo a los registros
Este último programa ilustra la posibilidad de acceder directamente a los registros de un archivo binario. Muestra el registro del archivo data.bin, cuyo número se le pasa como parámetro, siendo el primer registro el que lleva el número 1.
// clases importadas
import java.io.*;
import java.util.*;
public class test6{
// archivo de texto --> archivo binario
// la estructura del artículo
private static class article{
// se define la estructura
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//clase «artículo»
// main
public static void main(String[] args){
// se comprueban los argumentos
int nbArguments=args.length;
String syntaxe="syntaxe : pg numéro_de_fiche";
if(nbArguments!=1)
erreur(syntaxe,20);
// comprobación del n.º de ficha
int numRecord=0;
try{
numRecord=Integer.parseInt(args[0]);
} catch(Exception e){
erreur(syntaxe+"\nNuméro de fiche incorrect",21);
}
// se abre el archivo binario en modo de lectura
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// se selecciona la ficha deseada
try{
dataBin.seek((numRecord-1)*40);
} catch (Exception e){
erreur("La fiche "+numRecord+" n'existe pas",23);
}
// se lee
article art=new article();
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
// se muestra
affiche(art);
// ya está
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",2);
}//try-catch
}// fin de main
// método de lectura
public static void lire(RandomAccessFile fic, article art) throws IOException{
// código de lectura
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// nombre
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// precio
art.prix=fic.readDouble();
// stocks
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fin de escritura
// ---------------------visualización
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);
}// fin de visualización
// ------------------------error
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// fin de error
}// fin de clase
Estos son algunos ejemplos de ejecución:
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 expresiones regulares
4.11.1. El paquete java.util.regex
El paquete java.util.regex permite el uso de expresiones regulares. Estas permiten comprobar el formato de una cadena de caracteres. De este modo, se puede verificar que una cadena que representa una fecha tenga efectivamente el formato dd/mm/aa. Para ello, se utiliza un patrón y se compara la cadena con dicho patrón. Así, en este ejemplo, j, m y a deben ser números. El patrón de un formato de fecha válido es, por tanto, «\d\d/\d\d/\d\d», donde el símbolo \d representa un dígito. Los símbolos que se pueden utilizar en un patrón son los siguientes (documentación de Microsoft):
Carácter | Descripción |
\ | Marca el carácter siguiente como carácter especial o literal. Por ejemplo, «n» corresponde al carácter «n». «\n» corresponde a un carácter de nueva línea. La secuencia «\\» corresponde a «\», mientras que «\»(» corresponde a «(». |
^ | Corresponde al inicio de la entrada. |
$ | Corresponde al final de la entrada. |
* | Corresponde al carácter anterior cero o más veces. Así, «zo*» corresponde a «z» o a «zoo». |
+ | Corresponde al carácter anterior una o varias veces. Así, «zo+» corresponde a «zoo», pero no a «z». |
? | Coincide con el carácter anterior cero o una vez. Por ejemplo, «a?ve?» coincide con «ve» en «lever». |
. | Coincide con cualquier carácter único, excepto el carácter de nueva línea. |
(patrón) | Busca «modèle» y memoriza la coincidencia. La subcadena correspondiente se puede extraer de la colección Matches obtenida, utilizando «Item [0]...[n]». Para encontrar coincidencias con caracteres entre paréntesis ( ), utiliza «\(» o «\)». |
x|y | Coincide tanto con x como con y. Por ejemplo, «z|foot» coincide con «z» o con «foot». «(z|f)oo» coincide con «zoo» o con «foo». |
{n} | n es un número entero no negativo. Se corresponde exactamente con n multiplicado por el carácter. Por ejemplo, «o{2}» no se corresponde con la «o» de «Bob», sino con las dos primeras «o» de «fooooot». |
{n,} | n es un número entero no negativo. Corresponde al menos a n veces el carácter. Por ejemplo, «o{2,}» no coincide con la «o» de «Bob», sino con todas las «o» de «fooooot». «o{1,}» equivale a «o+» y «o{0,}» equivale a «o*». |
{n,m} | m y n son números enteros no negativos. Corresponde a un número de veces del carácter que va desde, como mínimo, n hasta, como máximo, m. Por ejemplo, «o{1,3}» corresponde a las tres primeras «o» de «foooooot» y «o{0,1}» equivale a «o?». |
[xyz] | Conjunto de caracteres. Coincide con uno de los caracteres indicados. Por ejemplo, «[abc]» coincide con la «a» de «plat». |
[^xyz] | Conjunto de caracteres negativo. Corresponde a cualquier carácter no indicado. Por ejemplo, «[^abc]» corresponde a la «p» de «plat». |
[a-z] | Rango de caracteres. Corresponde a cualquier carácter de la serie especificada. Por ejemplo, «[a-z]» corresponde a cualquier letra minúscula comprendida entre «a» y «z». |
[^m-z] | Rango de caracteres negativo. Corresponde a cualquier carácter que no se encuentre en la serie especificada. Por ejemplo, «[^m-z]» corresponde a cualquier carácter que no se encuentre entre «m» y «z». |
\b | Corresponde a un límite que representa una palabra; es decir, a la posición entre una palabra y un espacio. Por ejemplo, «er\b» corresponde a «er» en «lever», pero no a «er» en «verbe». |
\B | Corresponde a un límite que no representa una palabra. «en*t\B» corresponde a «ent» en «bien entendu». |
\d | Corresponde a un carácter que representa un número. Equivale a [0-9]. |
\D | Corresponde a un carácter que no representa un número. Equivale a [^0-9]. |
\f | Corresponde a un carácter de salto de página. |
\n | Corresponde a un carácter de nueva línea. |
\r | Equivale a un carácter de retorno de carro. |
\s | Equivale a cualquier espacio en blanco, incluyendo el espacio, la tabulación, el salto de página, etc. Equivale a «[ \f\n\r\t\v]». |
\S | Corresponde a cualquier carácter de espacio no en blanco. Equivale a «[^ \f\n\r\t\v]». |
\t | Corresponde a un carácter de tabulación. |
\v | Corresponde a un carácter de tabulación vertical. |
\w | Corresponde a cualquier carácter que represente una palabra e incluya un guión bajo. Equivale a «[A-Za-z0-9_]». |
\W | Corresponde a cualquier carácter que no represente una palabra. Equivale a «[^A-Za-z0-9_]». |
\num | Corresponde a num, donde num es un número entero positivo. Hace referencia a las correspondencias almacenadas. Por ejemplo, «(.)\1» corresponde a dos caracteres idénticos consecutivos. |
|
Un elemento de una plantilla puede aparecer una o varias veces. Veamos algunos ejemplos relacionados con el símbolo \d, que representa un dígito:
plantilla | significado |
\d | un dígito |
\d? | 0 o 1 dígito |
\d* | 0 o más dígitos |
\d+ | 1 o más dígitos |
\d{2} | 2 dígitos |
\d{3,} | al menos 3 dígitos |
\d{5,7} | entre 5 y 7 dígitos |
Imaginemos ahora el modelo capaz de describir el formato esperado para una cadena de caracteres:
cadena buscada | modelo |
una fecha en formato dd/mm/aa | \d{2}/\d{2}/\d{2} |
una hora en formato hh:mm:ss | \d{2}:\d{2}:\d{2} |
un número entero sin signo | \d+ |
una secuencia de espacios, que puede estar vacía | \s* |
un número entero sin signo que puede ir precedido o seguido de espacios | \s*\d+\s* |
un número entero que puede ser con signo y estar precedido o seguido de espacios | \s*[+|-]?\s*\d+\s* |
un número real sin signo que puede ir precedido o seguido de espacios | \s*\d+(.\d*)?\s* |
un número real que puede ser con signo y estar precedido o seguido de espacios | \s*[+|]?\s*\d+(.\d*)?\s* |
una cadena que contenga la palabra «justo» | \bjusto\b |
Se puede especificar dónde se busca el patrón en la cadena:
patrón | significado |
^patrón | el patrón comienza la cadena |
patrón$ | el patrón termina la cadena |
^patrón$ | el patrón comienza y termina la cadena |
patrón | el patrón se busca en toda la cadena, empezando por el principio de la misma. |
cadena buscada | patrón |
una cadena que termina con un signo de exclamación | !$ |
una cadena que termina en un punto | \.$ |
una cadena que comienza con la secuencia // | ^// |
una cadena que contiene solo una palabra, seguida o precedida opcionalmente de espacios | ^\s*\w+\s*$ |
una cadena que contenga dos palabras, que pueden ir precedidas o seguidas de espacios | ^\s*\w+\s*\w+\s*$ |
una cadena que contenga la palabra «secret» | \bsecret\b |
Los subconjuntos de un patrón pueden «extraerse». De este modo, no solo se puede comprobar si una cadena se ajusta a un patrón concreto, sino que también se pueden extraer de dicha cadena los elementos que corresponden a los subconjuntos del patrón que se han encerrado entre paréntesis. Así, si analizamos una cadena que contiene una fecha dd/mm/aa y, además, queremos extraer los elementos dd, mm y aa de dicha fecha, utilizaremos el patrón (\d\d)/(\d\d)/(\d\d).
4.11.2. Comprobar que una cadena se ajusta a un patrón determinado
La clase Pattern permite comprobar si una cadena se ajusta a un patrón determinado. Para ello, se utiliza el método estático
con: modèle: el patrón que se va a comprobar; chaine: la cadena que se va a comparar con el patrón. El resultado es el valor booleano true si la cadena coincide con el patrón, y false en caso contrario.
He aquí un ejemplo:
import java.io.*;
import java.util.regex.*;
// gestión de expresiones regulares
public class regex1 {
public static void main(String[] args){
// una expresión regular de patrón
String modèle1="^\\s*\\d+\\s*$";
// comparar un ejemplo con el patrón
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);
}//muestra
}//clasifica
y los resultados de la ejecución:
Cabe señalar que, en el patrón «^\s*\d+\s*$», el carácter \ debe duplicarse debido a la interpretación particular que Java hace de este carácter. Por lo tanto, se escribe: String patrón1 = "^\\s*\\d+\\s*$";
4.11.3. Buscar todos los elementos de una cadena que coincidan con un patrón
Consideremos el patrón «\d+» y la cadena « 123 456 789 ». El patrón aparece en tres posiciones diferentes de la cadena. Las clases Pattern y Matcher permiten recuperar las distintas ocurrencias de un patrón en una cadena. La clase Pattern es la que gestiona las expresiones regulares. Una expresión regular que se utilice más de una vez debe «compilarse». Esto acelera las búsquedas del patrón en las cadenas. El método estático compile se encarga de ello:
Toma como parámetro la cadena del patrón y devuelve un objeto Pattern. Para comparar el patrón de un objeto Pattern con una cadena de caracteres se utiliza la clase Matcher. Esta permite comparar un patrón con una cadena de caracteres. A partir de un objeto Pattern, es posible obtener un objeto de tipo Matcher con el método matcher:
input es la cadena de caracteres que debe compararse con el patrón.
Así, para comparar el patrón «\d+» con la cadena « 123 456 789 », se puede crear un objeto Matcher de la siguiente manera:
A partir del objeto résultats anterior, podremos recuperar las diferentes ocurrencias del patrón en la cadena. Para ello, utilizamos los métodos suivantes de la clase Matcher:
El método find busca en la cadena analizada la primera aparición del patrón. Una segunda llamada a find buscará la siguiente aparición. Y así sucesivamente. El método devuelve true si encuentra el patrón; de lo contrario, devuelve false. La parte de la cadena correspondiente a la última aparición encontrada por find se obtiene con el método group y su posición con el método start. Así, si continuamos con el ejemplo anterior y queremos mostrar todas las apariciones del patrón «\d+» en la cadena « 123 456 789 », escribiremos:
while(résultats.find()){
System.out.println("séquence " + résultats.group() + " trouvée en position " + résultats.start());
}//while
El método reset permite reiniciar el objeto Matcher al principio de la cadena comparada con el patrón. De este modo, el método find volverá a encontrar la primera aparición del patrón.
A continuación se muestra un ejemplo completo:
import java.io.*;
import java.util.regex.*;
// gestión de expresiones regulares
public class regex2 {
public static void main(String[] args){
// varias ocurrencias del patrón en el ejemplo
String modèle2="\\d+";
Pattern regex2=Pattern.compile(modèle2);
String exemplaire3=" 123 456 789";
// búsqueda de ocurrencias del patrón en el ejemplo
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);
}//muestra
}//clasifica
Resultados de la ejecución:
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. Extraer partes de un patrón
Se pueden «extraer» subconjuntos de un patrón. De este modo, no solo se puede comprobar si una cadena se ajusta a un patrón concreto, sino que también se pueden extraer de dicha cadena los elementos correspondientes a los subconjuntos del patrón que se han encerrado entre paréntesis. Así, si analizamos una cadena que contiene una fecha dd/mm/aa y, además, queremos extraer los elementos dd, mm y aa de dicha fecha, utilizaremos el patrón (\d\d)/(\d\d)/(\d\d).
Veamos el siguiente ejemplo:
import java.io.*;
import java.util.regex.*;
// gestión de expresiones regulares
public class regex3 {
public static void main(String[] args){
// captura de elementos en la plantilla
String modèle3="(\\d\\d):(\\d\\d):(\\d\\d)";
Pattern regex3=Pattern.compile(modèle3);
String exemplaire4="Il est 18:05:49";
// verificación de la plantilla
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// el ejemplar se ajusta a la plantilla
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// se muestran los 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{
// el ejemplar no se corresponde con la plantilla
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
}//Principal
public static void affiche(String msg){
System.out.println(msg);
}//muestra
}//clasifica
Al ejecutar este programa se obtienen los siguientes 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
La novedad se encuentra en el siguiente fragmento de código:
// verificación del modelo
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// el ejemplar se corresponde con el modelo
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// se muestran los 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{
// el ejemplar no coincide con el modelo
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
La cadena exemplaire4 se compara con el patrón regex3 mediante el método find. A continuación, se encuentra una ocurrencia del patrón regex3 en la cadena exemplaire4. Si el patrón incluye subconjuntos entre paréntesis, estos están disponibles mediante diversos métodos de la clase Matcher:
public int groupCount()
public String group(int group)
public int start(int group)
El método groupCount proporciona el número de subconjuntos encontrados en el modelo y group(i), el subconjunto n.º i. Este se encuentra en la cadena en una posición determinada por start(i). Así, en el ejemplo:
L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13
La primera llamada al método find encontrará la cadena 18:05:49 y creará automáticamente los tres subconjuntos definidos por los paréntesis de la plantilla, que son 18, 05 y 49, respectivamente.
4.11.5. Un programa de aprendizaje
Encontrar la expresión regular que nos permita comprobar si una cadena se ajusta a un determinado patrón puede suponer, en ocasiones, todo un reto. El siguiente programa permite practicar. Solicita un patrón y una cadena y, a continuación, indica si la cadena se ajusta o no al patrón.
import java.io.*;
import java.util.regex.*;
// gestión de expresiones regulares
public class regex4 {
public static void main(String[] args){
// datos
String modèle=null,chaine=null;
Pattern regex=null;
BufferedReader IN=null;
Matcher résultats=null;
int nbOccurrences=0;
// gestión de errores
try{
// se solicita al usuario las plantillas y los ejemplares que se van a comparar con este
while(true){
// flujo de entrada
IN=new BufferedReader(new InputStreamReader(System.in));
// se solicita la plantilla
System.out.print("Tapez le modèle à tester ou fin pour arrêter :");
modèle=IN.readLine();
// ¿Terminado?
if(modèle.trim().toLowerCase().equals("fin")) break;
// se crea la expresión regular
regex=Pattern.compile(modèle);
// se le pide al usuario los ejemplares que se van a comparar con el modelo
while(true){
System.out.print("Tapez la chaîne à comparer au modèle ["+modèle+"] ou fin pour arrêter :");
chaine=IN.readLine();
// ¿Terminado?
if(chaine.trim().toLowerCase().equals("fin")) break;
// se crea el objeto «matcher»
résultats=regex.matcher(chaine);
// se buscan las ocurrencias del patrón
nbOccurrences=0;
while(résultats.find()){
// se ha encontrado una coincidencia
nbOccurrences++;
// se muestra
System.out.println("J'ai trouvé la correspondance ["+résultats.group()
+"] en position "+résultats.start());
// Visualización de los 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
// cadena siguiente
}//while(résultats.find())
// ¿se ha encontrado al menos una aparición?
if(nbOccurrences==0){
System.out.println("Je n'ai pas trouvé de correspondance au modèle ["+modèle+"]");
}//si
// patrón siguiente
}//while(true)
}//while(true)
}catch(Exception ex){
// error
System.err.println("Erreur : "+ex.getMessage());
// fin con error
System.exit(1);
}//try-catch
// fin
System.exit(0);
}//Main
}//clase
A continuación se muestra un ejemplo de ejecución:
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. El método split de la clase Pattern
Consideremos una cadena de caracteres compuesta por campos separados por una cadena separadora que se expresa mediante una expresión regular. Por ejemplo, si los campos están separados por el carácter , precedido o seguido de cualquier número de espacios, la expresión regular que modela la cadena separadora de los campos sería «\s*,\s*». El método split de la clase Pattern nos permite recuperar los campos en un array:
public String[] split(CharSequence input)
La cadena input se descompone en campos, separados por un separador que se ajusta al modelo del objeto Pattern actual. Para recuperar los campos de una línea cuyo separador de campos sea una coma precedida o seguida de cualquier número de espacios, se escribirá:
// una línea
String ligne="abc ,, def , ghi";
// un modelo
Pattern modèle=Pattern.compile("\\s*,\\s*");
// descomposición de una línea en campos
String[] champs=modèle.split(ligne);
Se puede obtener el mismo resultado con el método split de la clase String:
public String[] split(String regex)
A continuación se muestra un programa de prueba:
import java.io.*;
import java.util.regex.*;
// gestión de expresiones regulares
public class split1 {
public static void main(String[] args){
// una línea
String ligne="abc ,, def , ghi";
// una plantilla
Pattern modèle=Pattern.compile("\\s*,\\s*");
// descomposición de una línea en campos
String[] champs=modèle.split(ligne);
// visualización
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
// otra forma de hacerlo
champs=ligne.split("\\s*,\\s*");
// visualización
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
}//Principal
}//clase
Resultados de la ejecución:
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
4.12. Ejercicios
4.12.1. Ejercicio 1
En Unix, los programas suelen ejecutarse de la siguiente manera:
$ pg -o1 v1 v2 ... -o2 v3 v4 …
donde -oi representa una opción y vi un valor asociado a dicha opción. Se desea crear una clase «options» que permita analizar la cadena de argumentos -o1 v1 v2 ... -o2 v3 v4 … con el fin de construir las siguientes entidades:
optionsValides | diccionario (Hashtable) cuyas claves son las opciones oi válidas. El valor asociado a la clave oi es un vector (Vector) cuyos elementos son los valores v1 v2 … asociados a la opción -oi |
optionsInvalides | diccionario (tabla hash) cuyas claves son las opciones «oi» no válidas. El valor asociado a la clave «oi» es un vector (Vector) cuyos elementos son los valores v1, v2… asociados a la opción «-oi» |
optionsSans | cadena (String) que proporciona la lista de valores vi no asociados a ninguna opción |
erreur | entero igual a 0 si no hay errores en la línea de argumentos; en caso contrario, otro valor: 1: hay parámetros de llamada no válidos 2: hay opciones no válidas 4: hay valores no asociados a opciones Si hay varios tipos de errores, estos valores se suman. |
Un objeto «options» se puede crear de cuatro formas diferentes:
public options (String arguments, String optionsAcceptables)
arguments | la línea de argumentos -o1 v1 v2 ... -o2 v3 v4 … que se va a analizar |
optionsAcceptables | la lista de opciones oi aceptables |
Ejemplo de llamada: options opt=new options("-u u1 u2 u3 -g g1 g2 -x","-u -g");
En este caso, los dos argumentos son cadenas de caracteres. Se aceptarán los casos en los que estas cadenas se hayan dividido en palabras y se hayan almacenado en un array de cadenas de caracteres. Para ello se necesitan otros tres constructores:
public options (String[] arguments, String optionsAcceptables)
public options (String arguments, String[] optionsAcceptables)
public options (String[] arguments, String[] optionsAcceptables)
La clase «options» tendrá la siguiente interfaz (métodos de acceso):
devuelve la referencia de la tabla optionsValides creada al crear el objeto «options»
devuelve la referencia de la matriz optionsInvalides creada al crear el objeto «options»
devuelve la referencia de la cadena optionsSans generada al crear el objeto «opciones»
devuelve el valor del atributo «error» creado al crear el objeto de opciones
si no hay ningún error, muestra los valores de los atributos optionsValides, optionsInvalides, optionsSans; de lo contrario, muestra el número de error.
A continuación se muestra un programa de ejemplo:
import java.io.*;
//opciones de importación;
public class test1{
public static void main (String[] arg){
// apertura del flujo de entrada
String ligne;
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
affiche(e);
System.exit(1);
}
// lectura de los argumentos del constructor 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));
}// fin del bucle «while»
}//fin de main
public static void affiche(Exception e){
System.err.println("Erreur : "+e);
}
}//fin de la clase
Algunos 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. Ejercicio 2
Se desea crear una clase «stringtovector» que permita transferir el contenido de un objeto String a un objeto Vector. Esta clase derivaría de la clase Vector:
y tendría el siguiente código:
private void stringtovector(String S, String separateur, int[] tChampsVoulus,
boolean strict){
// crea un vector con los campos de la cadena S
// esta está formada por campos separados por «separador»
// si separador=null, la cadena forma un único campo
// solo se desean los campos cuyos índices se encuentran en la tabla tChampsVoulus
// son los deseados. Los índices comienzan en 1
// si tChampsvoulus es nulo o tiene tamaño nulo, se toman todos los campos
// si «strict» = «true», deben estar presentes todos los campos deseados
La clase tendría el siguiente atributo privado:
Este atributo lo establece el constructor anterior con los siguientes valores:
0: la construcción se ha realizado correctamente
4: faltan algunos campos requeridos, aunque strict=true
La clase también tendrá dos métodos:
que devuelve el valor del atributo privado erreur.
que muestra el valor del objeto en el formato (error, elemento 1, elemento 2, …) donde los elementos i son los elementos del vector construido a partir de la cadena.
Un programa de prueba podría ser el siguiente:
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());
}
}
Los 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)
Algunos consejos:
- Para dividir la cadena S en campos, utiliza el método split de la clase String.
- Colocar los campos de S en un diccionario D indexado por el número de campo
- Recuperar del diccionario D únicamente los campos cuya clave (índice) figure en la tabla tChampsVoulus.
4.12.3. Ejercicio 3
Se desea añadir a la clase stringtovector el siguiente constructor:
public stringtovector(String S, String separateur, String sChampsVoulus,boolean strict){
// crea un vector con los campos de la cadena S
// esta está formada por campos separados por «separador»
// si «separador» = nulo, la cadena forma un único campo
// solo se desean los campos cuyos índices estén en sChampsVoulus
// los índices comienzan en 1
// si sChampsvoulus = null o «», se toman todos los campos
// si strict=verdadero, deben estar presentes todos los campos deseados
Por lo tanto, la lista de campos deseados se encuentra en una cadena (String) en lugar de en una matriz de enteros (int[]). Al atributo privado erreur de la clase se le puede asignar un nuevo valor:
2: la cadena de los índices de los campos deseados es incorrecta
A continuación se muestra un programa de ejemplo:
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());
}
}
Algunos 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)
Algunos consejos:
- Hay que volver al caso del constructor anterior transfiriendo los campos de la cadena sChampsVoulus a una matriz de enteros. Para ello, hay que dividir sChampsVoulus en campos mediante un objeto StringTokenizer, cuyo atributo countTokens indicará el número de campos obtenidos. A continuación, se puede crear una matriz de enteros del tamaño adecuado y rellenarla con los campos obtenidos.
- Para saber si un campo es un entero, utilice el método Integer.parseInt para convertir el campo en un entero y gestione la excepción que se generará cuando esta conversión no sea posible.
4.12.4. Ejercicio 4
Se desea crear una clase «filetovector» que permita transferir el contenido de un archivo de texto a un objeto Vector. Esta clase derivaría de la clase Vector:
y tendría el siguiente constructor:
// --------------------- constructor
public filetovector(String nomFichier, String separateur, int [] tChampsVoulus,boolean strict, String tagCommentaire){
// crea un vector con las líneas del archivo de texto nomFichier
// las líneas están formadas por campos separados por un separador
// si separador=null, la línea forma un único campo
// solo se desean los campos cuyos índices se encuentren en tChampsVoulus
// Los índices comienzan en 1
// si tChampsvoulus es nulo o está vacío, se toman todos los campos
// si «strict» = verdadero, deben estar presentes todos los campos deseados
// si no es así, la línea no se almacena y su índice
// se coloca en el vector lignesErronees
// las líneas en blanco se ignoran
// así como las líneas que comienzan por tagCommentaire si tagCommentaire != null
La clase tendría los siguientes atributos privados:
El atributo erreur es establecido por el constructor anterior con los siguientes valores:
0: la construcción se ha realizado correctamente
1: no se ha podido abrir el archivo que se iba a procesar
4: faltan algunos campos requeridos, aunque strict=true
8: se ha producido un error de E/S al procesar el archivo
El atributo lignesErronees es un vector cuyos elementos son los números de las líneas erróneas en forma de cadena de caracteres. Una línea se considera errónea si no puede proporcionar los campos solicitados cuando strict=true.
La clase también tendrá dos métodos:
que devuelve el valor del atributo privado erreur.
que muestra el valor del objeto en el formato (error, elemento 1, elemento 2…, (l1, l2,…)), donde los elementos i son los elementos del vector construido a partir del archivo y li son los números de las líneas con errores.
A continuación se muestra un ejemplo de prueba:
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 de la ejecución:
[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,# comentario) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# comentario) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Algunos consejos
-
El archivo de texto se procesa línea por línea. La línea se divide en campos mediante la clase
**stringtovector,** que ya hemos visto anteriormente. -
Los elementos del vector creado a partir del archivo de texto son, por lo tanto, objetos de tipo
**stringtovector**. -
El método identite de filetovector podrá utilizar el método stringtovector.identite() para mostrar sus elementos, así como el método Vector.toString() para mostrar los números de las posibles líneas erróneas.
4.12.5. Ejercicio 5
Se desea añadir a la clase «filetovector» el siguiente constructor:
public filetovector(String nomFichier, String separateur, String sChampsVoulus,
boolean strict, String tagCommentaire){
// crea un vector con las líneas del archivo de texto nomFichier
// las líneas están formadas por campos separados por un separador
// si separador=null, la línea forma un único campo
// solo se desean los campos cuyos índices se encuentren en tChampsVoulus
// Los índices comienzan en 1
// si sChampsvoulus es nulo o está vacío, se toman todos los campos
// si «strict» = verdadero, deben estar presentes todos los campos deseados
// si no es así, la línea no se almacena y su índice
// se coloca en el vector lignesErronees
// las líneas en blanco se ignoran
// así como las líneas que comienzan por tagCommentaire si tagCommentaire != null
La lista de índices de los campos deseados se encuentra ahora en una cadena de caracteres (String) en lugar de estar en una matriz de números enteros.
El atributo privado erreur puede tener un valor adicional:
2: la cadena de índices de los campos deseados es incorrecta
Aquí tienes un ejemplo de prueba:
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());
}
}
Los 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,# comentario) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# comentario) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Algunos consejos
- Convertiremos la cadena sChampsVoulus en una matriz de números enteros tChampVoulus para volver al caso del constructor anterior.