TEMA 6: STRINGS, I/O, FORMATEANDO Y PARSEANDO
TEMA 6: STRINGS, I/O, FORMATEANDO Y PARSEANDO
1.1 String, StringBuilder y StringBuffer.
1.1.2 StringBuffer y StringBuilder
2.1.1. Acceso a la entrada/salida estándar a través de la clase System.
2.3. Serializando utilizando el paquete java.io.
2.4. Trabajando con fechas, números y monedas: Calendar, dateFormat, date, locale, numberFormat
1.1 String, StringBuilder y StringBuffer.
Para tratar cadenas alfanuméricas, en Java 1.6 existen tres tipos de clases principales: String, StringBuilder, StringBuffer.
A continuación, vamos a comentar las tres clases:
1.1.1 String
La principal característica y diferencia con respecto a StringBuilder y StringBuffer es que String no puede modificarse de manera intrínseca. Es decir, las operaciones que realicemos sobre una clase String modificar el trozo de memoria reservado para el mismo.
El siguiente ejemplo es bastante descriptivo:
package es.scjp.javahispano.tema6;
public class P61Strings {
/**
* @param args
*/
public static void main(String[] args) {
// EJEMPLO CON STRING
String a = new String("JAIME");
// a vale Jaime y hay un trozo en
// memoria con la constante énAIMEy un
// puntero que apunta a ella.
a = new String("JOSE");
// a vale Jose y hay dos trozo en memoria, uno
// con la constante énAIMEy otro con la
// constante énOSE apuntando la variable a a
// énOSE
a.concat(" ANTONIO");
// a sigue valiendo Jose y hay tres trozos
// ocupados en memoria, "JAIME", "JOSE" y
// "ANTONIO".
// IMPORTANTE: los Strings no se modifican en sí mismos
System.out.println(a);
// Sin embargo, lo siguiente asigna a la variable a "JOSE ANTONIO", pues
// asigna valores
a = a.concat(" ANTONIO");
System.out.println(a);
// En las siguientes léneas, vemos como StringBuffer y StringBuilder
// pueden modificarse de manera intrénseca, sin necesidad de asignarlos
// de nuevo a una variable
StringBuffer stringBuffer = new StringBuffer("JOSE");
stringBuffer.append(" ANTONIO");
System.out.println("Valor de StringBuffer " + stringBuffer);
StringBuilder stringBuilder = new StringBuilder("JOSE");
stringBuilder.append(" ANTONIO");
System.out.println("Valor de StringBuilder " + stringBuilder);
}
}
Cuando se define un valor String, se reserva un trozo de memoria, y se rellena con los valores indicados. La variable que ha creado el String, si ha habido alguna, apunta al mismo.
El String no se puede modificar en si mismo. Esto es, el valor definido en la memoria de Java no es modificable en smismo, pudiéndose crear valores derivados del mismo, que ocupan su lugar en la memoria.
Por ejemplo, en el siguiente código:
java.lang.String a = "hello";
System.out.println(a);
a = "jaime";
System.out.println(a);
En la línea 4 tendremos una variable a, que apunta a un trozo de la memoria de Java que define una constante Jaime y después, tendremos una variable en la memoria, que no es referenciada por ninguna variable.
Sin embargo, vemos en el código anterior que para modificar la variable a tendremos que reasignarla de manera continúa a la misma variable o bien a otra. Lo que trato de decir es que, en este caso, el String referenciado no puede modificarse en si mismo, al ser realmente el String un trozo de memoria almacenado en la pila de memoria de Java, y ser la variable que lo apunta, en este caso, una variable que apunta a este trozo de memoria, y no tener privilegios sobre la misma que servir de apuntadora.
La clase String tiene los siguientes métodos importantes a tener en cuenta:
-charAt: devuelve el carácter que se encuentra en una posición determinada.
-indexOf:permite devolver el índice de un carácter.
-isEmpty: permite determinar si el String está vacío o no.
-length: permite calcular la longitud del String.
ES IMPORTANTE NO CONFUNDIR length de String con size de array.
1.1.2 StringBuffer y StringBuilder
Este caso, sin embargo, no pasa con StringBuffer. StringBuffer y StringBuilder son dos clases bastante similares: ambas se han definido para gestionar el manejo de cadenas en Java. Sin embargo, desde la JDK 1.5 se define StringBuilder, que contiene los mismos métodos que StringBuffer, con la diferencia de que sus métodos no estén sincronizados y por lo tanto no tienen restricciones a nivel concurrente. No entraremos en detalle en esta característica, simplemente diremos que la consecuencia de esto es que StringBuilder es mucho mén rénido que StringBuffer, y en los casos donde el rendimiento sea prioritario, se recomienda el uso del mismo en la mayoría de los casos, pues normalmente no tendremos que tratar problemas de concurrencia.
Veamos el siguiente ejemplo:
long tiempoInicio = System.currentTimeMillis();
for (int i = 0; i < 25000; i++) {
// String aux = ""+i;
StringBuffer strbuf = new StringBuffer();
strbuf.append(i);
}
long totalTiempo = System.currentTimeMillis() - tiempoInicio;
System.out.println("El tiempo de demora es :" + totalTiempo
+ " miliseg");
El tiempo de demora es :28 miliseg
Sin embargo, en el caso de StringBuilder, vemos lo siguiente:
tiempoInicio = System.currentTimeMillis();
for (int i = 0; i < 25000; i++) {
// String aux = ""+i;
StringBuilder strbuilder = new StringBuilder();
strbuilder.append(i);
}
totalTiempo = System.currentTimeMillis() - tiempoInicio;
System.out.println("El tiempo de demora es :" + totalTiempo
+ " miliseg");
El tiempo de demora es :18 miliseg
En este ejemplo hemos podido comprobar que StringBuilder es mucho mén réniido que StringBuffer.
Los métodos más relevantes de estas dos clases son los siguientes:
-append: el valor pasado como parámetro desde el carácter final ocupado.
-delete: elimina las casillas de los valores indicados por índice.
-insert: inserta desde la posición indicada los valores pasados como parámetro.
-replace: sustituye en los índices adecuados el String pasado como parámetro.
-setCharAt: establece en la posición indicada el carácter especificado.
-reverse: invierte el orden de las posiciones ocupadas.
Otro ejemplo importante para diferenciar StringBuffer y StringBuilder con String:
// En las siguientes léneas, vemos como StringBuffer y StringBuilder
// pueden modificarse de manera intrénseca, sin necesidad de asignarlos
// de nuevo a una variable
StringBuffer stringBuffer = new StringBuffer("JOSE");
stringBuffer.append(" ANTONIO");
System.out.println("Valor de StringBuffer " + stringBuffer);
StringBuilder stringBuilder = new StringBuilder("JOSE");
stringBuilder.append(" ANTONIO");
System.out.println("Valor de StringBuilder " + stringBuilder);
La salida en este caso es:
Valor de StringBuffer JOSE ANTONIO
Valor de StringBuilder JOSE ANTONIO
A MODO DE RESUMEN MUY RÁPIDO:
-String no puede modificarse en sí mismo, si no que necesita la reasignación a una variable.
-StringBuffer y StringBuilder permiten realizar modificaciones intrínsecas al objeto.
-StringBuilder es más rápido que StringBuffer, pues sus métodos no son sincronizados.
-En la mayoría de los casos, es recomendable usar StringBuilder para el tratado de textos por temas de rendimiento.
2.1. File I/O.
2.1.1. Acceso a la entrada/salida estándar a través de la clase System.
1) System.in: tiene los métodos read para leer un byte de la entrada, y skyp, para saltar n bytes de la entrada.
2) System.out: implementa stdout como una instancia de la clase PrintStream, que puede utilizar los métodos print() y println() con cualquier tipo básico de Java como argumento.
3) System.err: implementa stderr de la misma forma que stdout. Como con system.out, se tiene acceso a los métodos de PrintStream.
Veamos el siguiente ejemplo:
import java.io.*;
class miType {
public static void main( String args[] ) throws IOException {
int c;
int contador = 0;
while( (c = System.in.read() ) != '\n' )
{
contador++;
System.out.print( (char)c );
}
System.out.println(); // Línea en blanco
System.err.println( "Contados "+ contador +" bytes en total." );
}
}
2.2. Acceso sobre ficheros
- File: representación abstracta de un fichero.
- FileReader: se utiliza para leer caracteres de un fichero, normalmente se envuelve dentro de BufferedReader.
- BufferedReader: clase usada para que facilitar y hacer más eficiente el uso de FileReader, añadiendo además el método que permite leer líneas.
- FileWriter: análogo a FileReader, permite escribir caracteres en un fichero.
- BufferedWriter: análogo a BufferedReader, permite escribir caracteres en un fichero, de manera más eficiente, añadiendo, además de la posibilidad de escribir líneas.
Veamos el siguiente ejemplo:
package es.scjp.javahispano.tema6;
import java.io.*;
public class P622LeeFichero {
public static void main(String[] arg) {
File archivo = null;
FileReader fr = null;
BufferedReader br = null;
try {
// Apertura del fichero y creacion de BufferedReader para poder hacer una lectura comoda (disponer del metodo readLine()).
archivo = new File("C:\\archivo.txt");
fr = new FileReader(archivo);
br = new BufferedReader(fr);
// Lectura del fichero
String linea;
while ((linea = br.readLine()) != null)
System.out.println(linea);
} catch (Exception e) {
e.printStackTrace();
} finally {
// En el finally cerramos el fichero, para asegurarnos
// que se cierra tanto si todo va bien como si salta
// una excepcion.
try {
if (null != fr) {
fr.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
2.3. Serializando utilizando el paquete java.io.
Serializar un objeto significa darle al mismo la posibilidad de persistir su estado en un fichero externo, y después poder recuperarlo en el mismo estado.
Así mismo, nos permite que, en un modelo de trabajo cliente servidor, nos permita poder que, una variable concreta de un cliente, pueda ser enviada al servidor y este tenga la capacidad de reproducir el estado inicial en el que se encontraba dicha variable.
Para que una clase sea serializable, basta con que la misma implemente la interfaz del tipo Serializable.
Debemos saber que para que una clase sea serializable todos los atributos de la misma, si son una clase (puesto que las variables comunes, int, long, etc... son serializables por sí mismos al estar definidos como una secuencia de bits) deben ser serializables para que la clase padre o contenedora pueda ser serializable.
Lo vemos en el siguiente ejemplo:
public class EjemploSerializable implements Serializable{
int a;
int b;
Hijo c;
Aquí vemos que la clase EjemploSerializable tiene una referencia a un atributo c del tipo Hijo, que a su vez tiene la siguiente definición:
public class Hijo implements Serializable{
int a;
int b;
}
También podemos hacer que haya atributos que no queden persistidos a la hora de serializar el objeto, de la siguiente manera:
public class Hijo implements Serializable{
transient int a;
int b;
}
Esto quiere decir que el atributo a es de tipo transient, lo que quiere decir que, a la hora de persistir el objeto, sólo interesará almacenar el valor de la variable b.
El serialVersionUID sirve para definir el nénero de versién de clase. Este identificador nos permite diferenciar el número de versión de clase y nos permitirá discernir si el programa actual es capaz de leer instancias de clases persistidas anteriormente. Es probable que podamos serializar una clase, con una serie de atributos, y dejarla serializada, y más tarde, modificar nuestro programa para añadir más atributos.
Veamos el siguiente ejemplo:
public class P623Serializable implements Serializable{
private static final long serialVersionUID = 1376790362021476502L;
}
Al intentar recuperar una versién anterior, vemos que podemos tener problemas pues nuestra clase ha cambiado. Si hemos especificado el serialVersionUID el compilador detecta que hay un problema de compatibilidad de clases y podremos corregirlo, en caso contrario, tendremos un error muy desagradable, que es tener un error en el programa sin poder ser capaces de identificarlo, y, consecuentemente, corregirlo.
Por otra parte, es bueno añadir que, si queremos serializar colecciones o arrays, todos sus elementos internos deben ser serializables.
2.4. Trabajando con fechas, números y monedas: Calendar, dateFormat, date, locale, numberFormat
- Date: la mayoría de los métodos están obsoletos. Permite obtener la fecha actual, o bien la fecha a partir de un instante de tiempo especificado en milisegundos.
- Calendar: proporciona utilidades para hacer mén manejable el uso de fechas, dando métodos que permiten calcular el día actual, la semana, el mes, la fecha, hacer operaciones de comparación sobre la fecha, etc. Es una clase abstracta, además, proporciona variables estáticas.
- DateFormat: proporciona métodos que permiten manejarse correctamente con el formato de fechas, y adaptarlo según nuestros intereses.
- Locale: permite configurar formatos específicos de un idioma y/o registro, se puede aplicar, por ejemplo, a DateFormat.
Veamos el siguiente ejemplo:
public static void main(String args[]) {
//Obtenemos la fecha actual
Date ahora = new Date();
//Obtenemos un calendario griego
Calendar c = new GregorianCalendar();
//Asignamos la fecha actual a la actual
c.setTime(ahora);
//Obtenemos el primer dén de la semana
System.out.println(c.getFirstDayOfWeek());
//Formateamos la fecha a formato corto
System.out.println(DateFormat.getTimeInstance(DateFormat.SHORT).format(
ahora));
//Formateamos la fecha a formato mediano
System.out.println(DateFormat.getTimeInstance(DateFormat.MEDIUM)
.format(ahora));
//Formateamos la fecha a formato largo
System.out.println(DateFormat.getTimeInstance(DateFormat.LONG).format(
ahora));
//Creamos un locale para Ménico, para posteriormente, formatearlo.
Locale loc = new Locale("es","MX");
}
- NumberFormat: permite formatear los números correspondientes en Java. Los métodos más utilizados son: setMinimumIntegetDigits, setMinimumFractionDigits, setMaximumIntegerDigits y setMaximunFractionDigits.
package es.scjp.javahispano.tema6;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
public class P624Fechas {
public static void main(String args[]) {
// Obtenemos la fecha actual
Date ahora = new Date();
// Obtenemos un calendario griego
Calendar c = new GregorianCalendar();
// Asignamos la fecha actual a la actual
c.setTime(ahora);
// Obtenemos el primer dén de la semana
System.out.println(c.getFirstDayOfWeek());
// Formateamos la fecha a formato corto
System.out.println(DateFormat.getTimeInstance(DateFormat.SHORT).format(
ahora));
// Formateamos la fecha a formato mediano
System.out.println(DateFormat.getTimeInstance(DateFormat.MEDIUM)
.format(ahora));
// Formateamos la fecha a formato largo
System.out.println(DateFormat.getTimeInstance(DateFormat.LONG).format(
ahora));
}
}
La salida es la siguiente:
2
18:46
18:46:39
18:46:39 CEST
2.5. Expresiones regulares.
Java proporciona los siguientes métodos para la definición de patrones de búsqueda:
- Pattern.compile: permite compilar un patrón de búsqueda.
- Match: permite aplicar el patrón de búsqueda a un string concreto.
Un ejemplo de uso puede ser el siguiente:
package es.scjp.javahispano.tema6;
import java.util.regex.Pattern;
public class P65ExpresionesRegulares {
/**
* @param args
*/
public static void main(String[] args) {
// Create a pattern to match breaks
Pattern p = Pattern.compile("[,\\s]+");
// Split input with the pattern
String[] result = p.split("one, two, three, four, five");
for (int i = 0; i < result.length; i++)
System.out.println(result[i]);
}
}
La salida es la siguiente:
one
two
three
four
five
Reader Comments