/** @(#)Lab25.java 2010 Diferencia entre las clases String y StringBuffer de Java. @author Adolfo Di Mare */ import java.io.*; // Clases para leer desde el teclado import java.util.Scanner; // Clases para leer del teclado import java.io.DataInputStream; // Lectura multiplataforma de tipos básicos /** Clase que contiene el programa principal {@code main()}. */ public class Lab25 { /** Programa principal. */ public static void main( String args[] ) throws IOException { { String a = "una hilera"; String b = "otra hilera"; System.out.println( "a == " + a ); System.out.println( "b == " + b ); String c = a+" "+b; System.out.println( "c == " + c ); assertTrue( c == "una hilera otra hilera" ); c = c.replaceAll( "ra", "..." ); System.out.println( "c == " + c ); } /** Profe: ... ¿por qué me dijeron que no use String y que sí use StringBuffer? * * La clase String es INMUTABLE. Eso significa que al crear una hilera uno nunca * puede modificarla. * * En este código la orden c.replaceAll( "a", ".." ) no modifica el contenido de * la variable (c) sino que, a partir del valor de (c) construye una hilera nueva, * en donde las letras "ra" han sido remplazadas por "..". En consecuencia, el valor * "una hilera otra hilera" que contenía (c) queda descartado para que el recolector * de basura los recoja pues después de la operación replaceAll() el objeto (c) * referencia el nuevo valor String "una hile... ot... hile..." * * En contraposición, sí es posible modificar un objeto StringBuffer. Por eso, si uno * quiere leer un archivo letra por letra, agregando cada nueva letra al final de una * hilera, es mucho más eficiente usar StringBuffer. La ventaja que tiene la clase * String es que sí es una clase segura para implementar programas concurrentes con * múltiples tareas (multi-thread). */ { FileInputStream fis_Arch = new FileInputStream("Lab25.java"); System.out.println( "fis_Arch.available() == " + fis_Arch.available() ); StringBuffer lnArch = new StringBuffer( fis_Arch.available() ); assertTrue( lnArch.toString() == "" ); System.out.println( "lnArch == \"" + lnArch + "\""); { DataInputStream dis_Arch = new DataInputStream( fis_Arch ); try { for (;;) { // no existe dis_Arch.hasNext() byte b = dis_Arch.readByte(); char ch = (char)(b); lnArch.append( ch ); } } catch ( IOException e ) { System.out.print( lnArch ); } dis_Arch.close(); } } /** En este ejemplo, la variable (lnArch) comienza vacía pero con un tamaño previsto * de fis_Arch.available() caracteres. Conforme se lee cada letra, esta se agrega * al final de (lnArch). En este caso el archivo a leer Lab25.java está escrito * usando una codificación de caracteres de 8 bits en lugar de 16 bits, por lo que * la lectura se hace byte por byte. Para almacenar cada byte (de 8 bits) en la * variable (ch) [de 16 bits] hay que usar la conversión ch = (char)(b). * * Como la clase DataInputStream no incluye un método hastNext(), la forma de saber * que ya se terminó la lectura es atrapar la excepción que readByte() levanta * cuando llega al final del archivo. Otra forma de lograr lo mismo es leer * exactamente fis_Arch.available() letras, pero el método available() no siempre * retorna el tamaño real del archivo conectado al DataInputStream. */ } /** Simula el assertTrue() de JUnit. */ public static boolean assertTrue( boolean expr ) { return expr; } } /* EOF: Lab25.java */