|
|||||||||||||||||
![]() |
|||||||||||||||||
Pràctica |
![]() |
Exercicis
|
|||||||||||||||
Quan alguna cosa no va bé: la gestió d'excepcions | ||||||||||||||||||||
Què són les excepcions? | ||||||||||||||||||||
![]() |
Si ens permeteu el tòpic, quan es fa disseny de programari, si una cosa pot anar malament segur que anirà malament: un usuari teclejarà malament una informació, un fitxer desapareixerà màgicament del nostre ordinador, el nostre servidor estarà apagat quan intentem operar amb ell... Com que la casuística d'errors potencials és pràcticament inabastable, Java disposa d'un concepte particular, present a gairebé tots els llenguatges més moderns: el concepte d'excepció. Com tos els elements de Java, una excepció és un objecte que fa una tasca concreta: esperar que es produeixin errors o condicions estranyes en el programa. Si passa alguna eventualitat l'excepció ens avisa i ens ajuda a reconduir el problema tot intentant recuperar el funcionament normal de la nostra aplicació. Tot objecte excepció deriva de la classe java.lang.Throwable. Aquesta classe a més de la subclasse java.lang.Exception que ara estudiarem, en té una altra, la subclasse java.lang.Error. Si ens salta un error no hi ha res a fer: es tracta d'un problema del qual no ens en podrem recuperar i el programa s'aturarà. En canvi, si es produeix una excepció (exception) llavors podrem refer-nos-en. El funcionament és força senzill: el programador protegeix un bloc de codi amb la declaració d'una excepció. Si en l'execució d'aquell tros de programa es produeix un error, l'objecte excepció el captura i fa fluir el programa cap un fragment de codi on s'intentarà corregir l'esmentat error. Un cop corregit, intentarem retornar on estàvem i continuar amb normalitat. Què passa si no protegim el codi amb declaracions d'excepcions? El programa sempre intentarà trobar un gestor d'excepcions i si no el troba al lloc on s'ha produït, el buscarà al lloc des d'on hem cridat el mètode o la classe i així anirà pujant fins arribar a la Màquina Virtual de Java, la qual es limitarà a tancar el programa. De cara a l'usuari, un programa acabat així és un programa "trencat", sinònim de poca qualitat. Hem d'evitar que els errors arribin a la Màquina Virtual si no volem que ens facin quedar malament. |
|||||||||||||||||||
Planificant l'estratègia de captura d'errors | ||||||||||||||||||||
Davant d'una excepció podem actuar bàsicament de dues formes:
|
||||||||||||||||||||
En termes generals, si som capaços de preveure un problema potencial, hem d'intentar anticipar-nos-hi i donar-ne també la solució. El mètode més agraït de fer-ho és a través de l'estructura de control try-catch:
La lògica d'aquesta estructura és la següent: si es produeix qualsevol error a l'interior del bloc try{ }, es crea un objecte excepció -Exception e al nostre exemple- i el flux del programa salta dins del bloc catch{ } on hi haurem posat la solució del problema. En situacions molt elementals, les més freqüents, no ens caldrà ni recórrer al propi objecte Exception. Aquest és un cas ordinari de protecció i solució amb l'estructura try...catch:
Si intentem fer una conversió d'una cadena cadena a nombre enter (int), podem tenir problemes amb facilitat: que la cadena estigui buida o en estat null, que el seu contingut estigui format per lletres no traduïbles a nombre enter, etc. Amb una estructura com l'anterior, ens assegurem que, en cas d'error, nombre prendrà un valor i llavors el programa no es trencarà. Si a més vull obtenir detalls de l'error, (cosa que
em pot servir per depurar el programa,
per exemple) l'objecte Exception em donarà
aquests detalls:
El mètode e.getMessage() (de la classe java.lang.Throwable, classe mare de java.lang.Exception) ens retorna una cadena amb la descripció de l'error que acabem de tenir. Si el fem sortir per la pantalla, podem localitzar fàcilment on ens està fallant el programa. A la pràctica anterior hem construït un codi d'aquest tipus i l'hem vist treballar! En moltes ocasions ens resultarà útil concretar quin tipus d'excepció s'està produint o ens podrà interessar fer coses diferents segons el tipus d'excepció que s'hagi generat. Per a la gestió d'aquestes diferències no n'hi ha prou amb recollir una excepció genèrica, una instància de la classe java.lang.Exception. Haurem d'utilitzar alguna de les subclasses d'excepció predefinides al SDK de Java, o bé en podrem crear d'altres al nostre gust. Disposem d'una àmplia jerarquia d'excepcions. Visiteu la documentació de la classe java.lang.Exception i les trobareu totes definides. Aquí us en llistem algunes de les més usuals:
|
||||||||||||||||||||
Observeu ara com podem reaccionar de manera diferent segons la categoria de l'error: | ||||||||||||||||||||
![]() |
Si executem el programa tal com està, quan intentem dividir un nombre per zero es generarà una excepció ArithmeticException. La instrucció del programa davant d'un error d'aquest tipus és escriure en pantalla "Atenció, divisió per zero". Si comentem la línia "nombre /=0" i tornem a compilar i executar el programa, estarem creant una excepció de desbordament de matriu. Això passarà el control al bloc catch de gestió genèrica d'excepcions i obtindrem el missatge "S'ha produït un error!". |
|||||||||||||||||||
Creem les nostres pròpies excepcions! | ||||||||||||||||||||
![]() |
També, si ens interessa, podem crear les nostres pròpies excepcions, només ens cal extendre la classe java.lang.Exception. Imaginem el problema següent: el nostre director ens demana un programa que assigni alumnes a les aules i hem de vigilar que una aula no tingui mai més d'un nombre determinat d'alumnes. Com que aquesta situació de control es donarà força vegades, creem una excepció per a expressar-la: |
|||||||||||||||||||
Escrivim aquest petit programa de construicció
de l'excepció (en el capítol següent aprendrem
a fer paquets (packages)
i les classes amb totes les excepcions
personalitzades d'un programa es poden posar en un paquet).
Després, escrivim aquest programa de verificació d'ocupació d'aules
Hem creat una entrada de dades des del teclat on se'ns demana el nombre d'alumnes que ocuparan l'aula. Si intentem entrar un nombre superior a 30, el programa genera una excepció MassaAlumnesException:
Però no només la genera sinó que, en lloc de deixar-la pujar cap a la Màquina Virtual, la captura en el bloc try-catch i la gestiona: fa sortir per pantalla el missatge descriptor de l'excepció. Observeu que si errem en l'entrada de teclat -si escrivim lletres en lloc de nombres- també estem protegits gràcies a una excepció genèrica que, mitjançant el missatge "Error d'entrada de dades", ens informarà de l'error. |
||||||||||||||||||||
"throw" en el codi del mètode i "throws" a la declaració del mètode | ||||||||||||||||||||
Anterior ja hem vist com conviuen els diferents mètodes de gestió d'excepcions: hem utilitzat blocs try-catch per reaccionar davant problemes previsibles i hem utilitzat sentències "trow" i "throws". Endevineu la utilització d'ambdues fòrmules un cop posades al programa?
|
||||||||||||||||||||
![]() |
|
|||||||||||||||||||
|
||||||||||||||||||||
Finalment, demostrarem la utilitat de les excepcions en una situació de control de flux de programa. |
||||||||||||||||||||
![]() |
Control de la sortida del programa a través d'una excepció: | |||||||||||||||||||
Ens interessa que el nostre programa d'ocupació d'aules vagi demanant dades indefinidament fins que l'usuari digui prou. Amb la combinació d'un cicle indefinit i un gestor d'errors podem solucionar el problema. Escrivim aquesta versió modificada del programa MassaAlumnes.java: |
||||||||||||||||||||
|
||||||||||||||||||||
El cor del programa és la sentència for (;;;): És un cicle indefinit. S'anirà reproduint fins que fem saltar algun error que no sigui MassaAlumnesException. Si és d'aquest tipus la gestió de l'excepció es queda dins del cicle i no passa res. Si no ho és, l'excepció es propaga més enllà del cicle for (;;;) i s'acaba el programa. (for (;;;) és equivalent a while(true)). El resultat és que podem anar entrant dades indefinidament . Si assignem massa alumnes a una aula el programa ens avisa però continua treballant. Si l'error no és MassaAlumnesException, el programa ens informa del número d'aules que hem situat correctament i surt. Qualsevol entrada de teclat que no sigui un nombre enter produirà la sortida del programa: |
||||||||||||||||||||
![]() |
||||||||||||||||||||
![]() |
||||||||||||||||||||