14 nov 2014

La clase PrintWriter de Java

Características.

Clase que nos permite escribir con formato texto tanto en la salida estándar, como en ficheros, en cadenas, o en streams.

Hay que especificar, a través de los argumentos, dónde se va a producir la salida.

EJ. 1:   PrintWriter pw1= new PrintWriter(System.out);
EJ. 2:   PrintWriter pw2= new PrintWriter(new File("fichero.txt"));

A partir de la versión 5, incluso se permite:

Ej. 3:    PrintWriter pw2= new PrintWriter("fichero.txt");

Implementa todos los métodos de la clase PrintStream. A diferencia de esta clase, sus métodos de escritura no se vacían automáticamente al escribir una nueva línea.

Principales métodos.

o   print(), escribe el argumento. Está sobrecargado para los tipos primitivos.
pw.print(Hola, mundo);
pw.print(2050);

o   println(), escribe el argumento y salta de línea.

o   printf(), salida con formato, similar a C.
pw.printf(Saludo: %s %d %n, Hola, mundo, 2050);

o   flush(),  vacía el stream.

o   close(), cierra vaciando previamente el stream.

o   write(), escribe el argumento.
pw.write(Hola, mundo);


Ejemplo:

public static void main(String[] args){
    …
       FileWriter f = new FileWriter(“salida.txt”);
  PrintStream ps = new PrintStream(f);
  for (int[] fila : matriz) {
      String st = "";
      for (int value : fila) {
            st += value + delimiter;
            }
         ps.printf("%s%n", st);
     }
  ps.close();

}

13 nov 2014

Estructuras de control en Java - El bucle for – each


Dentro de las estructuras de control repetitivas, Java cuenta con los tradicionales while(), do-while() y for () con estructuras idénticas a las utilizadas en C y en C++, con la salvedad de la condición de iteración que tiene que ser un valor lógico, no valiendo un valor numérico.

Java además, a partir de la versión 5, incorpora el bucle, conocido como for each.
  • Se utiliza de manera especial para controlar arrays o en general colecciones. 
  • Tiene la ventaja de no tener que utilizar una variable para controlarlo. 
  • Su funcionamiento se basa en iterar para cada uno de los elementos de la colección, sin necesidad de conocer el número de elementos de los que consta.


El formato de este bucle es: 

for( tipo var_elto: var_array){
//instrucciones
}

Su funcionamiento, consiste en ir tomando cada elemento del array var_array, que serán del tipo tipo_var y lo copia en var_elto para su procesamiento.


Ejemplo, for each frente a for tradicional:

public static void main(String[] args){
    int[] lista = {1, 2, 3, 4};
     // recorrido del array
    for(int n : lista)
        System.out.println(n);
     // recorrido del array con el for tradicional
 for(int i=0; i< lista.length; i++ )
        System.out.println(lista[i]);
}


Ejemplo, con una colección:

public static void main(String[] args){
    …
  ArrayList<String> aList = new ArrayList<String>();
    aList.add(“Madrid”);
    aList.add(“Palencia”);
    aList.add(“Guadalajara”);
  // recorrido de una colección
    for(String s : aList)
        System.out.println(s);
}


Ejemplo, procesando una matriz por filas y columnas: 

public static void main(String[] args){
    int[][] matriz;
  for (int[] fila : matrix) {
         for (int elto : fila) {
                System.out.printf("%8d", elto);
            }
      System.out.printf(“%n");
     }
}


Equivalente con el for tradicional: 

public static void main(String[] args){
    int[][] matriz;
  for (int i=0; i < matriz.length; i++) {
         for (int j=0; j < matriz[0].length; j++) {
                System.out.printf("%8d", matriz[i][j]);
            }
      System.out.printf(“%n");
     }

}

4 nov 2014

Las Excepciones en Java

Las excepciones son situaciones anómalas que se producen en la ejecución de los programas, como puede ser una división por cero, o un fallo en la apertura de un fichero.
Mediante el mecanismo de excepciones se intentan poder recuperar la anomalía y que el programa pueda seguir funcionando.
Los errores son situaciones irrecuperables que se escapan al control del programador, como por ejemplo un fallo en la máquina virtual.
En Java tanto las excepciones y los errores son clases que  derivan de Throwable.




Desde el punto de vista del tratamiento de las excepciones se puede distinguir tres categorías:

o   Excepciones comprobadas, marcadas (checked exceptions). Su captura es obligatoria. Derivan directamente de Exception, pero no de Error ni de RuntimeException. Se producen al invocar determinados métodos de ciertas clases, por circunstancias internas al método. Si se invoca a algún método que pueda producir una excepción de este tipo es necesario capturarla para evitar un error de compilación. Por ejemplo, si se pasa al constructor de FileReader el nombre de un archivo, ese constructor puede lanzar una FileNotFoundException. Esa excepción debe ser notificada al usuario, al que posiblemente habrá que pedir un nuevo nombre de archivo.

o   Excepciones de ejecución, no comprobadas, o no marcadas (unchecked exceptions). Son aquellas que derivan de RuntimeException. Se caracterizan porque normalmente la aplicación no se puede recuperar frente a ellas. Por ejemplo, si se pasa un null al constructor del FileReader, éste lanzara una NullPointerException. La aplicación puede capturar esta excepción, pero tiene más sentido corregir el error lógico que hay en la aplicación, y que ha dado lugar esta excepción.
  
o   Errores. Son aquellas que derivan de Error directamente. Se deben a circunstancias ajenas al código del programa. Si el FileReader anterior consigue abrir el archivo y se produce un fallo en el disco, se lanzará un IOError. El programa debe notificar al usuario la aparición de este error, pero posiblemente no puede hacer otra cosa que mostrar un volcado de pila y concluir la ejecución del programa.


Las excepciones comprobadas o marcadas (checked exceptions), tienen que cumplir necesariamente el requisito de Captura o Especificación, es decir, todo bloque de código que lance una excepción de este tipo tiene que capturar esa excepción, o notificar que puede lanzar excepciones de ese tipo.

Las excepciones de ejecución o no comprobadas y los errores no están obligadas a cumplir el requisito de captura o especificación.

Para capturar una excepción, es preciso emplear un bloque catch():

catch(TipoDeExcepcionCapturado | OtroTipoDeExcepcion ex)
{
// Código que procesa esta excepción
}

Para notificar o especificar que un código pueden lanzar una excepción, es preciso emplear una sentencia throws:

throws Excepcion_1, Excepcion_2,... Excepcion_N;

Cuando se produce la excepción en un programa, se crea un objeto de la clase de excepción que se ha dado y se lanza a la línea de código donde ha tenido lugar.

El mecanismo de control de excepciones permite capturar el objeto lanzado y realizar una serie de acciones programadas para el tipo de excepción.

La forma de llevarlo a cabo es mediante el uso de las instrucciones try, catch y finally.

Estructura genérica para el tratamiento de excepciones:

try {
// Código vigilado
   }
catch(ExcepcionCapturada_1 ex1) {
// Código que procesa ex1
     }
catch(ExcepcionCapturada_2 ex2) {
// Código que procesa ex2
     }
finally {
// Código que se ejecuta siempre,
// tanto si se procesa una excepción como si no
     }



Try
o   Delimita el conjunto de líneas del programa donde se puede producir la excepción.  Cuando se produce, el control pasa al bloque de código Catch correspondiente a la excepción producida, pasándole el objeto asociado a la excepción producida.

Catch
o   Conjunto de instrucciones que tratan o procesan un determinado tipo de excepción.
o   Pueden aparecer varios bloques de este tipo seguidos. Cada uno se encargará de un tipo de excepción, o incluso pueden aparecer distintos bloques para clases de excepciones en distintos niveles de la jerarquía de clases. Por ejemplo un tratamiento específico para una subclase y otro más genérico para la clase.
o   Sólo se puede ejecutar un bloque catch, pasando el control al bloque Finally o al punto siguiente después del último catch, si no existiera Finally. Si para una excepción producida se pueden aplicar varios catch, se procederá de forma secuencial y se ejecutará el primero que esté en el código. Por ejemplo si se produce una excepción NullPointerException y tenemos un catch para tratar NullPointerException y otro catch más genérico para tratar RuntimeException, se ejecutará el que esté primero, por eso es más adecuado colocar los más específicos primero.

Finally
o   Instrucciones opcionales que se ejecutan siempre que aparezcan, independientemente de la opción catch que se haya ejecutado. Incluso se ejecutan aunque no se haya producido ninguna excepción en el bloque try.


/* Los desbordamientos de tipos no producen ni avisos ni excepciones por lo que deben ser vigilados por el programador */
package pruebaexcepciones;
public class PruebaExcepciones {
    public static void main(String[] args) {
        int n1, n2 = 0;
        n1 = Integer.MAX_VALUE;
        try {
            n2 = n1 + 1;  //desbordamiento de tipo, no tratado
            System.out.printf("n1 vale: %d, y n2 vale: %d%n", n1, n2);
        } catch (Exception e) { //este código no se va a ejecutar
            System.out.println("Exception ---> " + e);
        }
        System.out.printf("%nComentario entre un try y otro%n%n");
        try {
            n2 = n1 / 0;
        } catch (RuntimeException re) {
            System.out.println("Excepción ---> " + re);
        } finally {
            System.out.println("n2 vale: " + n2);
        }
        System.out.printf("Finalmente n1 vale: %d, y n2 vale: %d%n", n1, n2);
    }
}


El resultado de la ejecución es:
n1 vale: 2147483647, y n2 vale: -2147483648
--Comentario entre un try y otro--
Excepción ---> java.lang.ArithmeticException: / by zero
En finally, n2 vale: -2147483648
Última línea, n1 vale: 2147483647, y n2 vale: -2147483648

Si en lugar de dividir por cero, dividimos por 1, no se produce la excepción, pero la cláusula finally se ejecuta igualmente, aun no produciéndose excepción, y se obtiene:
n1 vale: 2147483647, y n2 vale: -2147483648
--Comentario entre un try y otro--
En finally, n2 vale: 2147483647
Última línea, n1 vale: 2147483647, y n2 vale: 2147483647


Ejemplo de excepción comprobada, o marcada (checked exception), tratada mediante trycatch para resolver una IOException:

public void escribirLista_2(File f) {
        PrintWriter salida = null;
        try {
            FileWriter fw = new FileWriter(f);
            salida = new PrintWriter(fw);
            salida.println(“Archivo " + f.getName());
            for (int i = 0; i < NUM_ELEMENTOS; ++i) {
                salida.println("El valor situado en la posición "
                               + i + " es " + lista.get(i));
            }
        } catch (IOException ex) {
            System.out.println("\nError al escribir el archivo " + f.getName());
            System.out.println(ex);
            if (null != salida) salida.close();
}
}


Ejemplo de excepción comprobada, o marcada (checked exception), notificada mediante throws (requisito de especificación) para resolver una IOException:

public void escribirLista_1(File f) throws IOException {
        FileWriter fw = new FileWriter(f);
        PrintWriter salida = new PrintWriter(fw);
        salida.println(“Archivo “ + f.getName());
     for (int i = 0; i < NUM_ELEMENTOS; ++i) {
            salida.println(“Valor “ + i + “ = “ + lista.get(i));
        }
        salida.close();
    }

En los dos ejemplos anteriores se pueden producir excepciones de ejecución, del tipo IndexOutOfBoundsException, por ejemplo si sobrepasáramos los límites de la lista. Estas excepciones son no comprobadas o no marcadas (unchecked exception), por lo que el compilador no exige tratarlas, pero para depurar el código, podríamos hacerlo:

…    try {
            FileWriter fw = new FileWriter(f);
            salida = new PrintWriter(fw);
            salida.println("Este es el archivo " + f.getName());
            for (int i = 0; i < NUM_ELEMENTOS; ++i) {
                salida.println("Valor " + i + " = " + lista.get(i));
            }
        } catch (IOException ex) {
            System.out.println("\nError al escribir el archivo " + f.getName());
            System.out.println(ex);
            if (null != salida) {
                salida.close();
            }
        } catch (IndexOutOfBoundsException ie) {
            System.out.println("Error en los límites de la lista\n");
            System.out.println(ie);
        } finally {
    


Propagación de excepciones

Cuando se produce una excepción y no es tratada, se propaga por la pila de llamadas, pasando a un nivel superior, hasta que encuentre un nivel que la trate o hasta que llegue al programa principal. En el caso de que en el programa principal tampoco se haga, pasará el control a la máquina virtual, que se encargará de hacer un volcado de memoria y de finalizar el programa.
En el caso de las excepciones marcadas, puede tratarse, o bien sólo notificarla incluyendo throws en la cabecera del método, para pasar el control a un nivel superior de la pila donde deberá ser tratada.


Lanzamiento de excepciones

En ocasiones puede ser necesario, o útil, lanzar una excepción para que sea tratada en otro punto de la aplicación.
La forma de hacerlo es mediante:
thow excepcion;
siendo excepcion un objeto de la clase Exception o de alguna de sus clases derivadas. Puede lanzarse desde cualquier punto del programa incluidas las cláusulas catch.
 Si se trata de una excepción marcada, deberá notificarse en la cabecera del método desde donde se lance.

Ejemplo 1, se lanza una excepción sin tratar y se captura en el nivel superior:

public class ClaseSuperior {
   public static void main(String[] args) {
 ClaseInferior ci = new ClaseInferior();
        try {
            ci.lanzar();
          // ci.lanzar_capturar_y_relanzar();
        } catch (Exception e) {
            System.out.println("\nExcepción capturada en main ClaseSuperior ---> " + e);
        }
    }
}
public class ClaseInferior{
    void lanzar() throws Exception {      
            System.out.println(“Método lanzar()\n");
            throw new Exception("Lanzada desde método lanzar\n");
}…}

Ejecución:
Método lanzar()
Excepción capturada en main ClaseSuperior ---> java.lang.Exception: Lanzada desde método lanzar


Ejemplo 2, se lanza una excepción, se trata y se relanza al nivel superior:

 public class ClaseInferior{
   void lanzar_capturar_y_relanzar() throws Exception {
        // Se lanza una excepción y se captura de inmediato y se relanza
        try {
            System.out.println("Prueba lanzar, capturar…()\n");
            throw new Exception("Lanzada desde try");
        } catch (Exception ex) {
            System.out.println("Excepción capturada en lanzar, capturar…()");
            System.out.println("\nSe relanza la excepción");
            throw ex;
        } finally {
            System.out.println(“Estamos en finally");
        }
    }
}

Ejecución:
Prueba lanzar, capturar()
Excepción capturada en lanzar, capturar()
Se relanza la excepción
Estamos en finally
Excepción capturada en main ClaseSuperior ---> java.lang.Exception: Lanzada desde try


Métodos más importantes de la clase Exception:

o   String getMessage()
Devuelve el mensaje asociado a la excepción sobre la que se aplica.
o   void printStackTrace()
Imprime en la consola el volcado de pantalla asociado a la excepción.
o   void printStackTrace(PrintStream ps)
o   void printStackTrace(PrintWriter pw)
Variantes de printStackTrace a los que se les puede pasar un PrintStream o un PrintWriter y que nos permitirá, por ejemplo, almacenar el volcado en un fichero.


Ejemplo 1 modificado:

package gestexcep;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class ClaseSuperior {
public static void main(String[] args) throws FileNotFoundException {
        // TODO code application logic here
        ClaseInferior ci = new ClaseInferior();
        PrintWriter pw = new PrintWriter("fichero.log");
        try {
            //ci.lanzar();
            ci.lanzar_capturar_y_relanzar();
        } catch (Exception e) {
            System.out.println("\nExcepción capturada en main ClaseSuperior ---> " + e);
            System.out.println(e.getMessage());
            e.printStackTrace(); //útil en modo depuración
            e.printStackTrace(pw);
            pw.close();
        }
    }
}

Ejecución:

Prueba lanzar, capturar()
Excepción capturada en lanzar, capturar()
Se relanza la excepción
Estamos en finally
Excepción capturada en main ClaseSuperior ---> java.lang.Exception: Lanzada desde try
Lanzada desde try
java.lang.Exception: Lanzada desde try
            at gestexcep.ClaseInferior.lanzar_capturar_y_relanzar(ClaseInferior.java:24)
            at gestexcep.ClaseSuperior.main(ClaseSuperior.java:28)