Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Manejo de excepciones • Manejo de Errores mediante Excepciones. Tipos de excepciones: Exception y RuntimeException • Manejadores de Excepciones • La cláusula try/catch • Búsqueda del manejador apropiado • Manejadores genéricos y específicos • La cláusula finally • Definición de Excepciones propias Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava En Java las excepciones se clasifican en: • Verificadas en Compilación (checked exception): son errores que el compilador verifica y que se espera que el programador las maneje en su programa. Por ej.: al intentar abrir un archivo desde el sistema de archivos, podría dispararse una excepción, ya que el archivo puede no existir. En ese caso una solución posible es pedirle al usuario que ingrese un nuevo nombre; otro ejemplo podría ser intentar de ejecutar una sentencia sql errónea en la base de datos. • No-Verificadas en Compilación (unchecked exception): representan errores de programación difíciles de preveer. Son excepciones disparadas automáticamente por el sistema de ejecución de JAVA. Por ejemplo, las excepciones aritméticas (división por cero), excepciones de referencias nulas (acceso a un objeto mediante un puntero nulo), excepciones de indexación (acceso a un elemento de un arreglo con un índice muy chico ó demasiado grande) y error de casting. JAVA no obliga a los programadores a manejar este tipo de excepciones. Manejo de errores - Excepciones Java usa excepciones para proveer manejo de errores a sus programas. Una excepción es un evento o problema que ocurre durante la ejecución de un programa que interrumpe el flujo normal de ejecución de instrucciones. Si una excepción no cuenta con la información necesaria para resolver el problema en el contexto en que sucedió se puede pasar el problema a un contexto de más alto nivel. Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Jerarquía de Excepciones Las objetos de tipo Exception son disparadas cuando ocurren condiciones anormales, que frecuentemente pueden ser manejadas por un código específico y recuperadas. Los objetos de tipo Error son disparados por problemas serios, relacionados con la máquina, la memoria o el procesador. Los errores son disparados por la JVM y los programadores no pueden hacer nada. ZipExceptionFileNotFoundException Exception Error ThreadDeath OutOfMemoryError*** “ unchecked “ (el compilador no chequea) ArithmeticException NullPointerException*** ** *** MiExceptionIOException “checked “ (el compilador chequea su manejo) Las excepciones en JAVA son instancias de Throwable ó de algún descendiente de Throwable.Excepciones que representan fallas de operaciones de I/O Excepciones que puede ser evitadas con código preventivo. Object Throwable RunTimeException Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Un ejemplo con majeo de archivos (1 de 3) import java.io.*; public class InputFile { private FileReader in; public InputFile (String filename) { in=new FileReader(filename); } public String getWord() { int c = 0; StringBuffer buf = new StringBuffer(); while ((c = in.read()) != -1) { if (Character.isWhitespace((char) c)) return buf.toString(); else buf.append((char) c); } return buf.toString(); } } Si compilamos la clase InputFile, el compilador nos da los siguientes dos errores: InputFile.java: 11: Warning: Exception java.io.FileNotFoundException must be caught, or it must be declared in throws clause of this method. in=new FileReader(filename); InputFile.java: 19: Warning: Exception java.io.IOException must be caught, or it must be declared in throws clause of this method. c=in.read(); El compilador detecta que tanto el constructor de la clase InputFile como el método getWord, no especifican ni capturan las excepciones que se pueden generar adentro de su alcance, por lo tanto rechaza la compilación. Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava in=new FileReader(filename); c=in.read(); El nombre pasado como parámetro al constructor de la clase FileReader no existe en el file system, por lo tanto el constructor disparará la excepción: java.io.FileNotFoundException. El método getWord() de nuestra clase InputFile, lee del objeto FileReader abierto en el constructor de la clase, usando el método read(). Este método dispara la excepción: java.io.IOException si por algún motivo no se puede leer. Al disparar estas excepciones, el constructor y el método read() de la clase FileReader (de la API) permiten que los métodos que los invocan capturen dicho error y lo recuperen de una manera apropiada. El compilador JAVA obliga a que toda excepción checked sea capturada ó especificada por este motivo nuestra clase InputFile no compila. En este punto tenemos dos opciones: 1) Arreglar al constructor de la clase InputFile y al método getWord() para que capturen y recuperen el error (usando bloques try-catch), ó 2) Pasar por alto los errores y darle la oportunidad a los métodos que invoquen al constructor y a los métodos de InputFile de que recuperen los errores (usando la cláusula throws en el encabezamiento). Un ejemplo con majeo de archivos (2 de 3) Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava import java.io.*; public class InputFile { private FileReader in; public InputFile (String filename) { try { in = new FileReader(filename); } catch (FileNotFoundException e) { System.out.println(“Error: “+e.getMessage()); } } public String getWord() throws IOException { int c = 0; StringBuffer buf = new StringBuffer(); while ((c = in.read()) != -1) { if (Character.isWhitespace((char) c)) return buf.toString(); else buf.append((char) c); } return buf.toString(); } } Un ejemplo con majeo de archivos (2 de 3) Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Búsqueda de un manejador apropiado Cuando un método dispara una excepción, crea un objeto Throwable que es transferido al sistema de ejecución de JAVA, quién comienza a buscar un manejador de excepciones adecuado en la pila de ejecución. La búsqueda comienza en el método donde se disparó la excepción y luego continúa en la pila de ejecución de métodos en el orden inverso en que los métodos fueron invocados. Cuando el sistema de ejecución encuentra un manejador apropiado, le transfiere el control junto con la excepción lanzada. Un manejador de excepciones es adecuado si el tipo de la excepción declarada es del tipo de la disparada. Pila de ejecución Supongamos como muestra la figura que el método leerArchivo() dispara una IOException: crea un objeto IOException en la Heap (new); se interrumpe el flujo normal de ejecución y el objeto excepción es lanzado del contexto actual. El sistema de ejecución de Java comienza a buscar dónde continuar la ejecución: busca un manejador de la excepción apropiado en la pila de ejecución para recuperar el problema. m1(){ m2(); } m2(){ leerArchivo(); } leerArchivo() throws IOException{ ......... } main() m1() m2() leerArchivo() Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Capturar y Manejar Excepciones (try/catch) El bloque try: encierra las sentencias JAVA que podrían disparar excepcionesEl bloque catch: es un bloque de código que implementa el manejador de excepciones import java.io.*; public class EscribirNumerosEntrada { public static void main(String[] args) { PrintWriter out = null; int suma = 0; try { out = new PrintWriter(new FileWriter("doc.txt")); for (int i = 0; i < args.length; i++) { suma = +Integer.parseInt(args[i]); } out.write("La suma es: "+suma); out.close(); } catch (IOException e1) { System.err.println("Excepción de IO: " + e1.getMessage()); } catch (NumberFormatException e2) { System.err.println("Uno de los argumento no es entero:” + e2.getMessage()); } } } RunTimeException Exception El constructor de FileWriter dispara una IOException si el archivo es un directorio (en lugar de un archivo regular) y no puede crearse ó no puede crearse por alguna razón El método parseInt() dispara una NumberFormatException si el parámetro recibido no es un entero. Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava El mecanismo de manejo de excepciones comienza buscando el primer manejador cuyo tipo de argumento coincida con el tipo de la excepción disparada. Luego, se ejecuta el bloque catch del manejador seleccionado y la excepción se considera manejada. Solamente se ejecuta el bloque catch cuyo argumento es del mismo tipo que el de la excepción disparada. La coincidencia entre el tipo de la excepción disparada y la de su manejador no tiene que ser exacta: el tipo del manejador puede ser el de cualquier superclase de la excepción disparada. ¿Qué ocurre si se dispara una excepción en el bloque try? import java.io.*; public class EscribirNumerosEntrada { public static void main(String[] args) { PrintWriter out = null; int suma = 0; try { out = new PrintWriter(new FileWriter("doc")); for (int i = 0; i < args.length; i++) { suma = +Integer.parseInt(args[i]); } out.write("La suma es: "+suma); out.close(); } catch (IOException e1) { System.err.println("Excepción de IO: " + e1.getMessage()); } catch (NumberFormatException e2) { System.err.println("Uno de los argumento no es entero:” + e2.getMessage()); } System.err.println(“Fin de la suma y escritura”); }} ¿Cuál es la salida si doc es una carpeta? Excepción de IO: doc (Acceso denegado) Fin de la suma y escritura ¿Qué ocurre si adentro del try invocamos a diferentes métodos que disparan IOException? Podemos usar el mismo manejador. Si necesitamos manejadores diferentes -> debemos usar más de un bloque catch 1 2 3 Capturar y Manejar Excepciones Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Manejadores Genéricos y Especializados catch (FileNotFoundException e) { ......... } También es posible capturar un error basado en su grupo ó tipo general, especificando alguna de las superclases de FileNotFoundException: catch (IOException e) { ......... } Se puede averiguar la excepción específica usando el parámetro e. Requiere agregar código en el manejador. Es posible establecer un manejador más general que capture cualquier tipo de excepción catch (Exception e) { ......... } Los manejadores de excepciones muy generales hacen el código propenso a errores pues capturan y manejan excepciones que no fueron previstas y por lo tanto no se manejan correctamente. No son útiles para recuperación de errores. Un manejador de excepciones específico es aquel que maneja un tipo determinado de error. Puede hacerse un mejor manejo del error. Capturar y Manejar Excepciones (try/catch) Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava public void metodo() { PrintWriter out=null; try{ out=new PrintWriter(new FileWriter("doc")); . . . } catch(Exception e){ System.err.println("Exception capturada"); } catch(IOException e) { System.err.println("IOException capturada"); } } catch(IOException e) { System.err.println(“IOException capturada"); } catch(Exception e) { System.err.println(“Exception capturada"); NO!! NO COMPILA!!! pues se especificó un manejador inalcanzable: Unreachable catch block for IOException. It is already handled by catch block for Exception Está bien el código? Siempre que se especifique un manejador general y uno específico, primero debe especificarse el específico y luego el general, sino el programa NO compilará. Un bloque try tiene bloques catch que capturan errores generales y específicos, importa el orden Manejadores Genéricos y Especializados Capturar y Manejar Excepciones (try/catch) Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava El bloque finally Antes de que el control sea transferido a otra parte del programa, podemos definir un bloque finally que siempre se ejecutará. Comúnmente se usa para cerrar un archivo abierto, cerrar una conexión de red, borrar algo que hemos dibujado en la pantalla, etc. import java.io.*; public class EscribirNumerosEntrada { public static void main(String[] args) { PrintWriter out = null; int suma = 0; try { out = new PrintWriter(new FileWriter("doc")); for (int i = 0; i < args.length; i++) { suma = +Integer.parseInt(args[i]); } out.write("La suma es: "+suma); out.close(); } catch (IOException e1) { System.err.println("Excepción de IO: " + e1.getMessage()); } catch (NumberFormatException e2) { System.err.println("Uno de los argumento no es entero:” + e2.getMessage()); } System.err.println(“Fin de la suma y escritura”); }} } finally { if (out !=null){ System.out.println(“Cerrando el archivo”); out.close(); } else System.ou.println(“El archivo no se abrió”); } System.out.println(“Fin de la suma y escritura”); } } El sistema de ejecución de Java siempre ejecuta las sentencias del bloque finally independientemente de lo sucedido en el bloque try. Garantizamos que out se cierre siempre: (1) Si se dispara una IOException (2) Si se dispara una NumberFormatExceptio o cualquiera RunTimeExcpetion (3) Si no hay errores Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Propagar Excepciones JAVA provee una sintaxis que permite informarle al programador las excepciones que podrían disparar los métodos que usa. Si las excepciones no se manejan, JAVA fuerza a propagar o a especificacar las excepciones. La Especificación de Excepciones es parte de la declaración del método y se escribe después de la lista de argumentos. Es parte de la interface pública del método. Se usa la palabra clave throws seguida por una lista de tipos de excepciones que podrían dispararse en el alcance del método. Si un método NO captura ni maneja las excepciones chequeables disparadas adentro de su alcance, el compilador JAVA fuerza al método a propagarlas o especificarlas en su declaración. En algunas situaciones es mejor que un método propague las excepciones, por ejemplo si se está implementando una librería de clases, es posible que no se puedan prever las necesidades de todos los usuarios de la librería. En este caso, es mejor no capturar las excepciones y permitir que los usuarios que la usan codifiquen el tratamiento de excepciones. public void metodo() throws IOException { PrintWriter out=null; try{ out=new PrintWriter(new FileWriter(”salida.txt”)); . . . // se escriben datos en el archivo } finally { if (out!=null) out.close(); } } Podríamos propagar la excepción y usar el bloqye try/finally para asegurarnos de que siempre se cierre el objeto PrintWriter Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Crear excepciones propias (1/2) Problema de conexiónpublic class ServerTimeOutException extends Exception { private int port; public ServerTimeOutException() { super(); } public ServerTimeOutException(String message) { super(message); } public ServerTimeOutException(String message, int port) { super(message); this.port = port; } public int getPort() { return port; } } Las excepciones definidas por los usuarios deben ser subclases de la clase Exception para que sean chequeables. Las clases de tipo Exception pueden contener lo que contiene cualquier clase. El uso del método getMessage() heredado desde la clase Exception nos permitirá recuperar el mensaje de nuestra excepción. La siguiente clase es una Exception propia que será disparada cuando un servidor no responda: Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava public class Conectar { . . . public void conectame(String nombreServer) throws ServerTimeOutException { boolean exito=false; int port=80; exito = open(nombreServer, port); if (!exito) throw new ServerTimeOutException(“no se pudo conectar”); } } La siguiente clase Conectar dispara la excepción que acabamos de crear si no se puede conectar al servidor que recibe por parámetro: Para disparar la excepción que acabamos de crear se utiliza esta sintaxis . Usamos el constructor con sólo un argumento El método open() retorna false si en 5’’ no se puede conectar Manejando métodos que disparan excepciones chequeables: public void buscarServidor() { try { con.conectame(servidorDefault); } catch (ServerTimeOutException e) { System.out.println("Servidor "+ e.getMessage() + " fuera deservicio"); } } método que dispara una excepción que hay que manejar Crear excepciones propias (1/2) Problema de conexión Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Crear excepciones propias (1/5) Café Virtual Throwable Exception TemperatureException TooColdException TooHotException Cuando se diseña un paquete de clases JAVA, éstas deben interactuar bien y sus interfaces deben ser fáciles de entender y de usar. Para ello, es bueno diseñar clases de excepciones. Las condiciones excepcionales que pueden ocurrir cuando el cliente toma una taza de café son las siguientes: el café está muy frío o muy caliente. class TemperatureException extends Exception { } class TooColdException extends TemperatureException{ } class TooHotException extends TemperatureException { } Convención de nombres: es una buena práctica agregar el string “Exception” a todos los nombres de clases que heredan directa ó indirectamente de la clase Exception. Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Definimos la clase VirtualPerson que dispara excepciones en caso de que la temperatura esté por debajo de la mínima o sea superior a la máxima. class CoffeeCup { // 75 grados Celsius: temperatura ideal del café private int temperature = 75; public void setTemperature(int val){ temperature = val; } public int getTemperature() { return temperature; } } class VirtualPerson { private static final int tooCold = 65; private static final int tooHot = 85; public void drinkCoffee(CoffeeCup cup) throws TooColdException, TooHotException { int temperature = cup.getTemperature(); if (temperature <= tooCold) { throw new TooColdException(); } else if (temperature >= tooHot) { throw new TooHotException(); } } } Se dispara una excepción Se declaran las excepciones que puede disparar el método drinkCoffee() Crear excepciones propias (2/5) Café Virtual Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava class VirtualCafe { public static void serveCustomer(VirtualPerson cust, CoffeeCup cup) { try { cust.drinkCoffee(cup); System.out.println(”El Café está OK."); } catch (TooColdException e) { System.out.println(”El Café está muy frío."); } catch (TooHotException e) { System.out.println(”El Café está muy caliente."); } } . . . } El método drinkCoffee puede disparar las excepciones: TooHotException ó TooColdException catch (TemperatureException e) { System.out.println(”El Café..); } Se recomienda el uso de manejadores de excepciones especializados. Los manejadores genéricos - que agrupan muchos tipos de excepciones- no son útiles para recuperación de errores, ya que el manejador tiene que determinar que tipo de excepción ocurrió, para elegir la mejor estrategia para recuperar el error. Las clases TooColdException y TooHotException podrían tener una variable de instancia con la temperatura. Crear excepciones propias (3/5) Café Virtual Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Crear excepciones propias (4/5) Café Virtual abstract class TemperatureException extends Exception { private int temperature; public TemperatureException(int temperature) { this.temperature = temperature; } public int getTemperature() { return temperature; } } class TooColdException extends TemperatureException { public TooColdException(int temperature) { super(temperature); } } class TooHotException extends TemperatureException { public TooHotException(int temperature) { super(temperature); } } Agregamos información a las excepciones Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Ahora la clase VirtualPerson dispara excepciones con más información class VirtualPerson { private static final int tooCold = 65; private static final int tooHot = 85; public void drinkCoffee(CoffeeCup cup) throws TooColdException, TooHotException { int temperature = cup.getTemperature(); if (temperature <= tooCold) { throw new TooColdException(temperature); } else if (temperature >= tooHot) { throw new TooHotException(temperature); } } } Se dispara una excepción Crear excepciones propias (5/5) Café Virtual Contamos con la temperatura exacta que produjo la excepción Taller de Lenguajes II – Ingeniería en Computación – 2012 Prof. Claudia Queiruga - Prof. Laura Fava Sobrescritura de método y Excepciones Cuando se sobrescribe un método solamente se pueden disparar las excepciones especificadas en la versión de la clase base del método. La utilidad de esta restricción es que el código que funciona correctamente para un objeto de la clase base, seguirá funcionando para un objeto de la clase derivada (principio fundamental de la OO). La interface de especificación de excepciones de un método puede reducirse y sobrescribirse en la herencia, pero nunca ampliarse. public class A{ public void f() throws AException{ } public void g() throws BException, CException { } } public class B extends A{ public void f(){ } public void g() throws DException{ } } class AException extends Exception {} class BException extends AException {} class CException extends AException {} class DException extends BException {} public class Test{ public static void main(String[] args){ try { A x= new A(); x.f(); x.g(); } catch (BException e) {} catch (CException e) {} catch (AException e) {} } }
Compartir