Excepciones Excepciones Condiciones inesperadas en un programa Pueden ocurrir al llamar métodos de objetos Programación Orientada a Objetos Facultad de Informática Ejemplos Juan Pavón Mestras Dep. Ingeniería del Software e Inteligencia Artificial Universidad Complutense Madrid Se pueden tratar en el nivel donde ocurren (quien invoca el método) O en un nivel superior de la pila de llamadas Abrir un fichero que no existe Intentar invocar un método en un objeto que no existe (referencia null) Utilizar un array fuera de su rango Se cae una conexión de red que se estaba utilizando Inconsistencia del estado del objeto Falta una información para realizar una operación Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones if ( función(parámetros) == UN_ERROR ) { // tratar error } else { // código normal } En el código de los métodos se puede indicar la ocurrencia de la excepción y esto ocasiona la finalización inmediata del método • Por ejemplo el incumplimiento de alguna condición necesaria para la ejecución del método • También pueden ocurrir excepciones del entorno (no originadas explícitamente por la aplicación) • Síncronas: división por cero, acceso fuera de los límites de un array, puntero nulo • Asíncronas: algún fallo del sistema, caída de comunicaciones, falta de memoria El código del llamante se puede estructurar en dos partes: • Secuencia normal de ejecución • Tratamiento de excepciones: qué hacer cuando se sale del flujo normal de ejecución por la ocurrencia de alguna excepción • Por ejemplo, en C++ al quedarse sin memoria al hacer new o cuando se cae una conexión Excepciones En lenguajes de POO modernos se estructura el tratamiento de excepciones: Mecanismo simple Pero complica el código (cuando hay varias funciones empiezan a anidarse los if-else) Hay errores de ejecución que no pueden capturarse fácilmente Juan Pavón Mestras Facultad de Informática UCM, 2006-07 2 Excepciones Tradicionalmente esto se hace devolviendo un valor la función llamada que indica si todo ha ido bien o no Excepciones 3 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 4 Excepciones en Java Las excepciones son objetos Excepciones en Java De la clase Exception, que hereda de Throwable Comprobadas, el compilador obliga a considerarla En Java puede haber dos tipos de excepciones: Excepciones que no requieren comprobarse • Errores y excepciones de ejecución • Clase RuntimeException Throwable Error Exception Excepciones que hay que comprobar • Todas las demás • Heredan de la clase Exception ExcepciónUsuario RuntimeException Cuando ocurre una excepción se dice que se lanza (throw) throw new Excepción(); Sin comprobación, las lanza la MVJ La excepción puede ser capturada para tratarla (catch) catch (Excepción e) { tratamiento(); } Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 5 Excepciones en Java Son las que puede lanzar la MVJ • Normalmente representan una condición fatal del programa • No las comprueba el compilador y es difícil saber cuándo y por qué pueden suceder NullPointerException ArrayIndexOutOfBoundsException • Cuando se envía un mensaje a un objeto null • Cuando se accede a un índice ilegal en un array • Pero a veces se puede considerar que alguna condición podría ocasionarlas • Se suelen tratar en algún nivel superior de forma genérica Comprobadas: Excepciones con comprobación • Si no se consideran en el código, el compilador indica un error • Estas excepciones son lanzadas por métodos que se usan en el código (por eso las reconoce el compilador) • El programador tiene que definir lo que hacer cuando ocurran Excepciones IOException • Clase genérica para las excepciones que se producen en operaciones de E/S Las comprueba el compilador Juan Pavón Mestras Facultad de Informática UCM, 2006-07 6 No comprobadas, subclases de RuntimeException: • Ocurren en tiempo de ejecución Excepciones Algunas excepciones comunes en Java Excepciones sin comprobación obligatoria Juan Pavón Mestras Facultad de Informática UCM, 2006-07 NoSuchMethodException ClassNotFoundException • Cuando no se encuentra un método • Cuando una aplicación intenta cargar una clase pero no se encuentra su definición (el fichero .class correspondiente) 7 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 8 Algunos errores comunes en Java Gestión de excepciones NoSuchMethodError La aplicación llama a un método que ya no existe en la definición de la clase NoClassDefFoundError Cómo se haga depende del diseño general del sistema La MVJ intenta cargar una clase pero no se encuentra • Suele ocurrir si el CLASSPATH no está bien o si la clase (.class) no está donde se espera ClassFormatError La MVJ intenta cargar una clase desde un fichero incorrecto 9 Excepciones Se pueden capturar múltiples excepciones Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 10 Bloque finally El orden de captura de las excepciones es importante Se manejan en un bloque try-catch (si no, se propagan hacia el llamante): public void unMétodo(){ try{ //código donde se puede lanzar la excepción e }catch(Exception e){ //código que gestiona la exception e } } • Suele ocurrir cuando el fichero .class está corrupto, o si no es un fichero .class Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Tratarla en el método que las captura Propagarla al método llamante • Si al final nadie captura la excepción, el programa acaba y se lista la traza de la pila de llamadas • Sólo puede ocurrir si la clase cambia su definición en tiempo de ejecución Hay dos mecanismos para gestionar una excepción: Las más genéricas se deberían capturar al final Se ejecuta siempre al final, después del último bloque catch Generalmente se utiliza para hacer limpieza • Cerrar ficheros, conexiones, etc. public void unMétodo(){ try{ // código donde se puede lanzar la excepción e1 // código donde se puede lanzar la excepción e2 }catch(MiExcepción e1){ // código que gestiona la exception e1 Exception }catch(Exception e2){ // código que gestiona la exception e2 } } public void miMétodo(){ try{ // código donde se puede lanzar la excepción e1 // código donde se puede lanzar la excepción e2 } catch(MiExcepción e1){ // código que gestiona la exception e1 } catch(Exception e2){ // código que gestiona la exception e2 } finally{ //código de limpieza, liberar recursos (close) } } MiExcepción Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 11 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 12 Propagación de excepciones Gestión genérica de excepciones Es la segunda estrategia, en vez del bloque try-catch Deja que sea el método llamante quien gestione la excepción Hay que declarar que el método puede lanzar la excepción Se puede capturar una excepción genérica para capturar todas las que sean de ese tipo y subtipos Por ejemplo, capturando Exception se pueden capturar todas las excepciones posibles Y capturando Throwable todas las excepciones y errores • Se utiliza la palabra clave throws en la declaración del método • Lo más genérico es imprimir la traza de la pila de llamadas y así se ve dónde ha ocurrido public void miMétodo() throws Exception{ //código que puede lanzar una excepción e } Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones public void miMétodo(){ try{ //código }catch(Throwable e){ System.out.println(e.printStackTrace()); } } 13 Definición de nuevas excepciones (de usuario) Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 14 Cómo lanzar excepciones Basta con heredar de la clase Exception Para lanzar una nueva excepción: 1. Crear la excepción con new ClaseExcepción 2. Usar la palabra clave throw Exception public class Banco{ public Cuenta crearCuenta (String cliente) throws CuentaRechazada { if (!listaNegra.esta(cliente)) return new Cuenta(cliente); else throw new cuentaRechazada(); } } ExcepciónJuego ExcepciónJugadaInválida Juan Pavón Mestras Facultad de Informática UCM, 2006-07 ExcepciónJugadorAusente Excepciones 15 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 16 Ventajas del mecanismo de excepciones readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } Separación del tratamiento de errores del resto del código del programa Ejemplo de código sin tratamiento de errores Flujo del programa más sencillo Evita manejos de códigos de error Propagación de errores a lo largo de la pila de llamadas a métodos Evitar retornos continuos en caso de error Evitar la necesidad de argumentos adicionales • Por ejemplo, el clásico boolean Agrupamiento y definición de tipos de errores como clases Jerarquías de excepciones Tratar errores a diferentes niveles de especificidad Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 17 Ejemplo de tratamiento de errores sin excepciones errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) errorCode = -1; } else errorCode = -2; } else errorCode = -3; close the file; if (theFileDidntClose && errorCode == 0) errorCode = -4; else errorCode = errorCode & -4; } else errorCode = -5; return errorCode; } Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 18 Ejemplo de tratamiento de errores con excepciones public void leeFichero (File f) { try { abre(f); determina_tamaño(f); asigna_memoria(tam); lee_fichero_en_memoria(f); cierra(f); } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } } 19 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 20 Ejercicio Excepciones en C++ Realizar un programa en el que haya una ventana con un campo de texto donde se pueda introducir un número y el programa saque en la ventana su raíz cuadrada Manejando excepciones tratar las siguientes situaciones: Mecanismo no original del lenguaje, incorporado en las versiones más recientes Utiliza el mismo mecanismo que Java, en tres fases: Intento de ejecución de un bloque de código try { // bloque de código-intento ... } Si se produce una circunstancia excepcional durante la ejecución se lanza la excepción if (condicion) throw "overflow"; La ejecución del programa se desvia a un sitio específico donde la excepción es capturada y se trata catch (...) { // bloque manejador de posibles excepciones ... } • Se introduce un número negativo • Se introduce un texto que no es un número Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 21 Excepciones en C++ Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Ejemplo: supóngase que quiere crearse un array de cien millones de enteros Ejemplo: no vale con intentar un if..else #include <iostream> using namespace std; int main() { int *x = 0; int y = 100000000; int main() { int *x = NULL; int y = 100000000; x = new int[y]; // fallará al hacer el new, nada puede salvarlo if(x) { x[10] = 0; cout << "Puntero: " << (void *) x << endl; delete[] x; } else { cout << "Memoria insuficiente." << endl; } cin.get(); return 0; x = new int[y]; // crash!!!! x[10] = 0; cout << "Puntero: " << (void *) x << endl; delete[] x; cin.get(); return 0; } Normalmente habrá un momento en que no quedará memoria y el programa abortará Juan Pavón Mestras Facultad de Informática UCM, 2006-07 22 Excepciones en C++ #include <iostream> using namespace std; Excepciones Excepciones } 23 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 24 Excepciones en C++ Excepciones en C++ Ejemplo: con excepciones se puede tratar el problema Clase base class exception { public: exception() throw() { } virtual ~exception() throw(); virtual const char* what() const throw(); }; #include <iostream> using namespace std; int main() { int *x; int y = 100000000; • La función what() debe devolver una cadena que indica la razón de la excepción try { x = new int[y]; x[0] = 10; cout << "Puntero: " << (void *) x << endl; delete[] x; } catch(std::bad_alloc&) { cout << "Memoria insuficiente" << endl; } Existe una forma de capturar cualquier excepción catch(...) { cout << "Excepción imprevista" << endl; } cin.get(); return 0; } Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 25 Excepciones en C++ Excepciones 26 Excepciones en C++ Ejemplo: excepciones en copia de ficheros Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Primero: definición de la clase de excepción Ejemplo: excepciones en copia de ficheros Primero: definición de la clase de excepción • Definición del método what() #include <iostream> #include <fstream> using namespace std; const char* CopiaEx::what() const throw() { switch(motivo) { case 1: return "Fichero de origen no existe"; case 2: return "No es posible abrir el fichero de salida"; } return "Error inesperado"; } class CopiaEx: public exception { public: CopiaEx(int mot) : exception(), motivo(mot) {} const char* what() const throw(); private: int motivo; }; Ejemplo de C++ con Clase: http://www.conclase.net/c/curso/index.php?cap=043b Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 27 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 28 Excepciones en C++ Excepciones en C++ Ejemplo: excepciones en copia de ficheros Utilización en el programa Ejemplo: excepciones en copia de ficheros • Cómo lanzar excepciones • Cómo capturar y tratar excepciones void CopiaFichero(const char* Origen, const char *Destino) { unsigned char buffer[1024]; int leido; ifstream fe(Origen, ios::in | ios::binary); if(!fe.good()) throw CopiaEx(1); int main() { char Desde[] = "excepcion.cpp"; // Este fichero char Hacia[] = "excepcion.cpy"; try { CopiaFichero(Desde, Hacia); } catch(CopiaEx &ex) { cout << ex.what() << endl; } // (2) cin.get(); return 0; ofstream fs(Destino, ios::out | ios::binary); if(!fs.good()) throw CopiaEx(2); do { fe.read(reinterpret_cast<char *> (buffer), 1024); leido = fe.gcount(); fs.write(reinterpret_cast<char *> (buffer), leido); } while(leido); fe.close(); fs.close(); } } Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 29 Excepciones en C++ y Java En C++ no es necesario declarar previamente las excepciones (en Java si no son Runtime, sí) Los objetos de excepción pueden ser de cualquier tipo Valen también tipos primitivos como int o bool Se puede definir una clase de excepción que no herede de ninguna predefinida class error_limites { public : int lim_inferior ; int lim_superior ; int valor ; error_limites(int inf, int sup, int v) { lim_inferior=inf; lim_superior=sup; valor=v; } } //… ejemplo de uso: if ( nota < 0 || nota > 10 ) throw error_limites (0, 10, nota); Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Utilización en el programa Excepciones 31 Juan Pavón Mestras Facultad de Informática UCM, 2006-07 Excepciones 30