4. Clases de uso común
En este capítulo presentamos varias clases de Java de uso común. Estas cuentan con numerosos atributos, métodos y constructores. En cada caso, solo presentamos una pequeña parte de las clases. Los detalles de estas se encuentran 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 cuenta con un archivo jdk, pero sin documentación. Esta se puede encontrar en el sitio web de Sun: http://www.sun.com. En la carpeta docs se encuentra un archivo index.html, que es el punto de partida de la ayuda del JDK:


El enlace API & Language que aparece arriba da acceso a las clases de Java. El enlace Demos/Tutorials es particularmente útil para obtener 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 tener un acceso rápido. El URL se encuentra en <jdk>\docs\api\index.html. Ahí se encuentran enlaces a cientos de clases Java del JDK. Al principio, la principal dificultad es saber qué hacen estas diferentes clases. Por lo tanto, en un primer momento, esta ayuda solo es útil si se conoce el nombre de la clase sobre la que se busca información. También puedes guiarte por los nombres de las clases, que normalmente indican la función de la clase.
Tomemos un ejemplo y busquemos información sobre la clase Vector, que implementa una matriz dinámica. Solo hay que 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:

Ahí 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 verificar sistemáticamente la definición completa de las clases utilizadas.
4.2. Las clases de prueba
Los ejemplos siguientes utilizan en ocasiones las clases personne y enseignant. A continuación, recordamos su definición.
public class personne{
// apellido, 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 cadenas de caracteres. Supongamos que nom es una variable de cadena de caracteres:
String nombre;
nom es una referencia a un objeto que aún no se ha 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, donde el primer carácter 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 un array 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 con 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) | reemplaza 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
}//clasifica
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. Por lo tanto, es un array de objetos cuyo tamaño puede variar con el tiempo, lo cual no es posible con los arrays estáticos que hemos visto hasta ahora. A continuación se presentan algunos campos, constructores o 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) | agrega 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 verdadero 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í hay 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[]){
// la 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 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 repetir lo que se ha hecho 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 un ArrayList son distintos. Fuera de este caso, se puede utilizar indistintamente uno u otro. A continuación se presentan 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) | agrega el objeto al que hace referencia obj a la lista |
void add(int índice, Object obj) | agrega el objeto al que hace referencia obj a la tabla 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 tabla 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 |
A continuación se muestra 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[]){
// la 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 clase
Los resultados obtenidos son los mismos que los anteriores.
4.6. La clase Arrays
La clase java.util.Arrays brinda acceso a métodos estáticos que permiten realizar diversas operaciones con las tablas, en particular ordenaciones y búsquedas de elementos. A continuación se presentan 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[] array, 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. El array debe estar ordenado 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 del array. |
Aquí hay 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)};
// clasificació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 tabla que se debe ordenar es una tabla de objetos personne. La clase personne está definida de manera 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 (se podría haber utilizado el nombre).
Los resultados de la ejecución son los siguientes:
Se podría haber procedido de otra manera 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 quedó 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 un objeto de este tipo mediante new java.util.Comparator(), y el texto que sigue {…} define la clase de la que se crea un objeto. A esto se le llama una clase anónima porque 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 simplemente llama al método compare1 de la clase sort2. Así, 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
;
// clasificació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» nombre2
// 0 si o1.nom es «igual a» nombre2
// +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 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
Aquí hemos procedido de manera un poco diferente a los ejemplos anteriores. Los dos objetos Comparator necesarios para los métodos sort y binarySearch se crearon y se asignaron 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
;
Se realiza una búsqueda dicotómica en la tabla amis dos veces en el generador de sort4:
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 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");
}//busca
El método binarySearch funciona con el comparador comparateur2, el cual 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 menor que 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 «es 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 tabla amis; el segundo, el nombre de la persona buscada.
4.7. La clase Enumeration
Enumeration es una interfaz y no una clase. Cuenta con los siguientes métodos:
public abstract boolean hasMoreElements() | devuelve verdadero si la enumeración aún tiene elementos |
public abstract Object nextElement() | devuelve la referencia del siguiente elemento de la enumeración |
¿Cómo se utiliza una enumeración? Por lo general, así:
Enumeration e=… // se recupera un objeto de enumeración
while(e.hasMoreElements()){
// utilizar el elemento e.nextElement()
}
Aquí hay 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. Un diccionario puede verse 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 en el diccionario; un elemento es un par (clave, valor) |
public Object put(Object key, Object value) | agrega 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 |
A continuación se muestra 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[]){
// la 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, se necesita un flujo de escritura. Para ello, se puede utilizar la clase FileWriter. Los constructores que se utilizan con mayor frecuencia son los siguientes:
FileWriter(String fileName) | crea el archivo con el nombre fileName; luego se puede escribir en él; cualquier archivo con el mismo nombre que ya exista 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 apéndice (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 controla el almacenamiento en búfer de las líneas. Cuando se establece en 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, en ocasiones 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í hay un programa que escribe algunas 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 al ejecutar el programa es el siguiente:
4.9.2. Leer
Para leer el contenido de un archivo, se necesita 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 cuenta con varios métodos para leer de 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 provenir 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;
// manejo 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 de 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. Agregamos 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 manejar archivos binarios, en particular aquellos con estructura fija, como los que se conocen en los lenguajes C/C++. A continuación se presentan algunos métodos y constructores útiles:
RandomAccessFile(String nombreArchivo, String modo) | constructor: abre el archivo indicado en el modo especificado. Este modo puede tomar los siguientes valores: r: apertura en lectura rw: apertura para 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 del archivo |
void seek(long pos) | coloca el cursor del archivo en el byte pos |
4.10.2. La clase «artículo»
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 esta manera, 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{
// prueba la escritura de una estructura (en el sentido de 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 verificar que la ejecución se haya realizado correctamente.
4.10.4. Leer un registro
// clases importadas
import java.io.*;
public class test2{
// prueba 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 acabó
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 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();
// existencias
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fin de escritura
// ---------------------mostrar
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
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 extensión del programa de escritura de un registro. Ahora escribimos varios registros en un archivo binario llamado data.bin. Los datos se toman 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 de 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 toman 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 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);
// apellido, 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 siguiente línea
}// fin del while
} catch (IOException E){
erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
}
// se acabó
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 verificar que este haya 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 sale bien, el archivo data.text debe 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 de 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 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 llegado al 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);
// ¿seguimos?
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
}// fin del 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();
// existencias
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fin de escritura
// ---------------------mostrar
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
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 de artículo
// main
public static void main(String[] args){
// se verifican los argumentos
int nbArguments=args.length;
String syntaxe="syntaxe : pg numéro_de_fiche";
if(nbArguments!=1)
erreur(syntaxe,20);
// verificación del número 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();
// existencias
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// fin de escritura
// ---------------------mostrar
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 validar el formato de una cadena de caracteres. De esta manera, se puede verificar que una cadena que representa una fecha esté en 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, d, m y a deben ser números. El patrón de un formato de fecha válido es, por lo 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 siguiente carácter 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. Por lo tanto, «zo*» corresponde a «z» o a «zoo». |
+ | Corresponde al carácter anterior una o más veces. Por lo tanto, «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». |
. | Corresponde a cualquier carácter único, excepto al carácter de línea nueva. |
(patrón) | Busca modèle y guarda 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 ( ), usa "\(" o "\)". |
x|y | Corresponde tanto a x como a y. Por ejemplo, «z|foot» corresponde a «z» o a «foot». «(z|f)oo» corresponde a «zoo» o a «foo». |
{n} | n es un número entero no negativo. Corresponde exactamente a n multiplicado por el carácter. Por ejemplo, «o{2}» no corresponde a la «o» en «Bob», sino a las dos primeras «o» en «fooooot». |
{n,} | n es un número entero no negativo. Corresponde a al menos 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 al menos n hasta, como máximo, m. Por ejemplo, «o{1,3}» corresponde a las tres primeras «o» en «foooooot» y «o{0,1}» equivale a «o?». |
[xyz] | Conjunto de caracteres. Corresponde a uno de los caracteres indicados. Por ejemplo, «[abc]» corresponde a la «a» en «plat». |
[^xyz] | Conjunto de caracteres negativo. Corresponde a cualquier carácter no indicado. Por ejemplo, «[^abc]» corresponde a la «p» en «plat». |
[a-z] | Rango de caracteres. Corresponde a cualquier carácter dentro de la serie especificada. Por ejemplo, «[a-z]» corresponde a cualquier letra minúscula 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 | Corresponde 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. Se refiere a las correspondencias almacenadas. Por ejemplo, «(.)\1» corresponde a dos caracteres idénticos consecutivos. |
|
Un elemento en una plantilla puede aparecer una o más 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 inicia y termina la cadena |
patrón | el patrón se busca en toda la cadena, comenzando por el inicio de esta. |
cadena buscada | patrón |
una cadena que termina con un signo de exclamación | !$ |
una cadena que termina con un punto | \.$ |
una cadena que comienza con la secuencia // | ^// |
una cadena que contiene solo una palabra, que puede ir seguida o precedida 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 «secreto» | \bsecret\b |
Los subconjuntos de un patrón pueden «extraerse». De este modo, no solo se puede verificar que una cadena coincida con un patrón específico, sino que también se pueden extraer de esa cadena los elementos que corresponden a los subconjuntos del patrón que se han rodeado de paréntesis. Por ejemplo, si analizamos una cadena que contiene una fecha dd/mm/aa y queremos además extraer los elementos dd, mm y aa de esa fecha, utilizaremos el patrón (\d\d)/(\d\d)/(\d\d).
4.11.2. Verificar que una cadena se ajuste a un patrón dado
La clase Pattern permite verificar si una cadena se ajusta a un patrón dado. Para ello, se utiliza el método estático
con: modèle: el patrón a verificar, chaine: la cadena a comparar con el patrón. El resultado es el valor booleano true si la cadena coincide con el patrón, false en caso contrario.
A continuación, 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 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+"]");
}//si
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 le da a 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 lugares diferentes de la cadena. Las clases Pattern y Matcher permiten recuperar las diferentes ocurrencias de un patrón en una cadena. La clase Pattern es la que maneja las expresiones regulares. Una expresión regular que se usa más de una vez debe ser «compilada». Esto acelera las búsquedas del patrón en las cadenas. El método estático compile realiza esta tarea:
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 se debe comparar 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 ocurrencia del patrón. Una segunda llamada a find buscará la siguiente ocurrencia. Y así sucesivamente. El método devuelve true si encuentra el patrón; de lo contrario, devuelve false. La porción de la cadena correspondiente a la última ocurrencia 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 ocurrencias 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 inicio de la cadena comparada con el patrón. De esta manera, el método find volverá a encontrar la primera ocurrencia del patrón.
A continuación se muestra un ejemplo completo:
import java.io.*;
import java.util.regex.*;
// manejo 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());
}//mientras
}//Principal
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 esta manera, no solo se puede verificar que una cadena coincida con un patrón específico, sino que también se pueden extraer de esa cadena los elementos que corresponden a los subconjuntos del patrón que se han encerrado entre paréntesis. Por ejemplo, si analizamos una cadena que contiene una fecha dd/mm/aa y queremos extraer además los elementos dd, mm y aa de esa 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 el modelo
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 corresponde al 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));
}//for
}else{
// el ejemplar no coincide con el modelo
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 la siguiente parte del código:
// verificación del modelo
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// el ejemplar corresponde al 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 devuelve el número de subconjuntos encontrados en el modelo y group(i) devuelve el subconjunto n.º i. Este se encuentra en la cadena en una posición dada 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, respectivamente 18, 05 y 49.
4.11.5. Un programa de práctica
Encontrar la expresión regular que nos permita verificar que una cadena se ajusta a un patrón determinado puede ser, en ocasiones, un verdadero desafío. El siguiente programa permite practicar. Solicita un patrón y una cadena, y luego 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 le pide al usuario los modelos y los ejemplares que se deben 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();
// ¿Listo?
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 compararán 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();
// ¿Listo?
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 encuentra una ocurrencia
nbOccurrences++;
// se muestra
System.out.println("J'ai trouvé la correspondance ["+résultats.group()
+"] en position "+résultats.start());
// se muestran 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
}//si
// siguiente cadena
}//mientras (résultats.find())
// ¿se ha encontrado al menos una ocurrencia?
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, los cuales están separados por un separador que corresponde al modelo del objeto Pattern actual. Para recuperar los campos de una fila cuyo separador de campos sea la 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";
// un modelo
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]+"]");
}//para
}//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 invocarse 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 contiene la lista de valores vi no asociados a una opción |
erreur | entero que toma el valor 0 si no hay errores en la línea de argumentos; de lo contrario, toma otro valor: 1: hay parámetros de llamada inválidos 2: hay opciones inválidas 4: hay valores no asociados a opciones Si hay varios tipos de errores, estos valores se suman. |
Un objeto de opciones 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");
Aquí, 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 colocado en un array de cadenas de caracteres. Esto requiere 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 generar el objeto de opciones
devuelve la referencia de la tabla optionsInvalides creada al generar el objeto de opciones
devuelve la referencia de la cadena optionsSans generada al crear el objeto de opciones
devuelve el valor del atributo de error creado al generar 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 del 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 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 constructor:
private void stringtovector(String S, String separateur, int[] tChampsVoulus,
boolean strict){
// crea un vector con los campos de la cadena S
// esta está compuesta por campos separados por separador
// si separador=nulo, la cadena forma un solo 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 de tamaño cero, se toman todos los campos
// si «strict» = verdadero, deben estar presentes todos los campos deseados
La clase tendría el siguiente atributo privado:
Este atributo es establecido por el constructor anterior con los siguientes valores:
0: la construcción se realizó 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, utilice 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) se encuentre en la tabla tChampsVoulus.
4.12.3. Ejercicio 3
Se desea agregar 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á compuesta por campos separados por separador
// si separador=nulo, la cadena forma un solo campo
// solo se desean los campos cuyos índices estén en sChampsVoulus
// los índices comienzan en 1
// si sChampsvoulus es nulo o está vacío, se toman todos los campos
// si strict=verdadero, todos los campos deseados deben estar presentes
Por lo tanto, la lista de los campos deseados se encuentra en una cadena (String) en lugar de en un array 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 con un objeto StringTokenizer, cuyo atributo countTokens indicará el número de campos obtenidos. A continuación, se puede crear un array de enteros del tamaño adecuado y llenarlo con los campos obtenidos.
- Para saber si un campo es un entero, utiliza el método Integer.parseInt para convertir el campo en un entero y maneja 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 compuestas por campos separados por un separador
// si el separador es nulo, la línea forma un solo 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 con 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 realizó correctamente
1: no se pudo abrir el archivo a procesar
4: faltan algunos campos requeridos, aunque strict=true
8: se produjo 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 con errores 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 vimos 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 con errores.
4.12.5. Ejercicio 5
Se desea agregar 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 compuestas por campos separados por un separador
// si separador=nulo, la línea forma un solo 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 con tagCommentaire si tagCommentaire != null
La lista de índices de los campos deseados ahora se encuentra 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 los índices de los campos deseados es incorrecta
Aquí hay 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 tabla de números enteros tChampVoulus para volver al caso del constructor anterior.