10.07.2015 Views

Excepcions a Java

Excepcions a Java

Excepcions a Java

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Excepcions</strong> a <strong>Java</strong>Algorísmica I - ETIG2 de març de 20091 IntroduccióControlar els errors en una aplicació és una tasca extremadament difícil. Lautilització de pre/post condicions ja ens ajuda a determinar quan es comportabé un tros de codi. Tot i això, sempre poden haver-hi imprevistos. . . Ens referimals errors d’execució deguts a situacions excepcionals, és a dir, quan el programaestà ben escrit però pel que sigui intenta fer quelcom que no es pot fer. Es tractade situacions fora de l’abast més proper de la tasca del programador: problemesamb l’entrada/sortida, esgotament de recursos, fitxer no existent. . . D’altrabanda, hi ha algunes situacions d’error, degudes a errors de programació, onsegurament sí que el programador té quelcom a dir-hi: demanar el cim d’unapila buida, tractar de fer un accés fora de rang a un vector,. . .Tinguem en compte que si un programa acaba la seva execució de maneraerrònia sense donar-nos cap pista de per què s’ha acabat, com ens ho faremper a detectar/tractar el possible error? Què s’ha de fer doncs en una situaciód’aquestes?• Res. El programa podria continuar anòmalament i destruir dades importants.• Intentar recuperar l’error, portant el flux del programa a una situaciócorrecta i, si no és possible, fer que el programa acabi de la manera menysnociva possible, informant de què ha passat.Ara cal respondre a la pregunta de com “controlar” els errors o situacionsexcepcionals. Les funcions/mètodes haurien d’indicar-nos d’alguna manera sis’ha produït alguna excepcionalitat durant la seva execució. Una possibilitatseria fer retornar un codi d’error a cada funció i comprovar sempre que no s’hagiproduït cap error. Com podem imaginar, això comporta molta feina, i complicael programa. A més, si la imatge de la funció és completa, com diferenciar elcodi d’error d’un valor possible?2 Les <strong>Excepcions</strong>La solució passa pel mecanisme de les excepcions, que consisteix en: quan esdetecta un error, parar l’execució del “bloc” on s’ha produït i anar a buscar una1


part de codi que se n’encarregui. Podem desglossar-ho en quatre fases:1. detectar condicions d’excepció (o errònies),2. llavors llançar una excepció, de manera que s’atura l’execució del mètodeon s’ha produït,3. saltar al codi que tracta l’excepció (si aquesta no es tracta, senzillamentacabar l’execució),4. continuar l’execució del programa després del tractament de l’excepció.<strong>Java</strong> proporciona una jerarquia de classes per controlar les excepcions. Lesexcepcions són objectes, i “llançar una excepció” consisteix, entre altres coses,en crear un objecte de tipus Exception. Aquest objecte conté informació sobre elque ha passat, i ens pot ajudar a recuperar l’error. Al cim de la jerarquia hi hala classe Throwable, que té com a subclasses Error i Exception. Exception té com asubclasses d’una banda totes les checked i d’una altra la RuntimeException d’onderiven les unchecked. Aquest dos tipus d’excepcions tenen algunes diferències:• Quan una funció/mètode pot llançar una checked exception, el compiladorde <strong>Java</strong> demana que s’indiqui a la capçalera que la pot llançar. Per a lesunchecked no cal.• Quan s’executa un codi que pot generar checked exceptions, aquestes s’hande tractar, o bé via try { codi que pot generar excepcions } catch(tipusd’excepció) { codi per tractar l’excepció }, o bé indicant que es propaguenvia throws. . . . Si es tracta de unchecked exceptions no cal tractar-les nipropagar-les si no es vol (senzillament s’aturaria l’execució).Les excepcions que es propaguen cap amunt (en el sentit de les crides fetes enel programa), podran ser tractades més amunt. Si l’excepció arriba al programaprincipal i no hi ha previst cap tractament, l’execució s’atura.3 Com Definir <strong>Excepcions</strong>La informació que ens proporcionen les excepcions pot ser molt útil fins i totper depurar els programes. En concret, el constructor de la classe Exception potrebre com a paràmetre un String que ens servirà per indicar, per exemple, la raóde l’excepció.Per tant, quan definim un nou tipus d’excepció, el primer que hem de ferés decidir si deriva de RuntimeException i per tant és unchecked o bé deriva deException i per tant és checked. Llavors simplement hem de redefinir com amínim els constructors.Per exemple, suposem que tenim definit un tipus ConjuntEnters i volem sercapaços de gestionar les situacions anòmales que es puguin produir. Així, creemun nou tipus d’excepcions ConjuntException, que en aquests cas seran checkedexceptions:2


class ConjuntException extends Exception {public conjuntException(){this.super();}public conjuntException(String s){this.super(s);}}Si volguéssim que fos unchecked senzillament hauríem de canviar Exceptionper RuntimeException.En general, ens pot interessar crear tipus nous d’excepcions per a les nostresclasses, i per tant seria bona idea que formessin part del mateix paquet. Tambépodria ser interessant definir-ne de generals, com per exemple per capturarviolacions de precondicions en els mètodes en general, llavors l’hauríem de posaren un paquet d’excepcions general.També és possible usar els tipus d’excepció propis del <strong>Java</strong>, és a dir, no ésimprescindible definir-ne de nous.4 Com Gestionar <strong>Excepcions</strong>4.1 GeneracióLa detecció d’errors o situacions excepcionals es durà a terme dins els mètodes.Per tant, el llançament d’excepcions també. Per generar una excepció cal:1. Especificar que el mètode llança/propaga l’excepció, utilitzant la paraulathrows just després de la capçalera, seguida dels tipus d’excepció que puguigenerar (de fet, això no és estrictament necessari si l’excepció és de tipusunchecked),2. saber detectar l’excepció i,3. una vegada detectada, llançar-la mitjançant la paraula clau throw seguidade l’excepció que es vulgui llançar. Aquesta s’haurà de crear llavors mateixmitjançant l’operador new seguit del constructor de l’excepció.Tornant a l’exemple del tipus ConjuntEnters, podem suposar que aquest té unmètode int tria(){. . . } que retorna un enter qualsevol del conjunt. Evidentment,demanar c.tria() quan c és buit, és una situació anòmala i la tractarem ambexcepcions:public int tria() throws ConjuntException{if(this.nelem==0)3


}throw new conjuntException("Conjunt.tria(): conjunt buit!");elsereturn(this.elements[this.nelem-1]);// Retornem p.ex. l’ultim4.2 Temptativa i CapturaPer poder “respondre” a l’excepció, el que es fa és posar dins d’un bloc detemptativa el codi que pot generar l’excepció de manera que, si es produeix,el flux d’execució anirà automàticament al final d’aquest bloc, concretament alque gestioni el tipus d’excepció produïda (o una superclasse d’aquesta). El blocde temptativa anirà a dins de try{. . . }, i els capturadors d’excepció tot seguit,especificant quin tipus d’excepció tracten i com la tracten catch(tipus excepciovar){. . . }.Seguint amb l’exemple del conjunt d’enters, podem veure com tractar lautilització del mètode tria():try {int k;ConjuntEnters c;c = new ConjuntEnters();k = c.tria();}catch(ConjuntException e){System.out.println("Error de programacio. " + e);System.out.println("Sequencia de crides: ");e.printStackTrace();}catch(Exception e){System.out.println(e);}System.out.println("L’execucio segueix normalment...");Fixem-nos que l’objecte que conté l’excepció, e, es pot utilitzar com a String,i és l’String que s’ha fet servir en llançar l’excepció (com a paràmetre del constructor).Això és perquè el mètode println automàticament invoca el mètodetoString de l’objecte.Com podem veure, podem tractar diferents tipus d’excepció. A més, <strong>Java</strong>també ens dóna l’oportunitat de definir un bloc al final dels catch que s’executaràsempre, hi hagi hagut o no excepcions. Aquest bloc és el finally{. . . }. Es posaràdesprés de l’últim catch, o just després del bloc try si hi hagués cap catch. Aquestbloc pot ser útil per intentar recuperar l’error. Cal tenir en compte que desprésl’execució continua de manera natural, amb el codi que hi ha a continuació.4


5 Quan i Com Utilitzar <strong>Excepcions</strong>D’alguna manera, les precondicions haurien de servir per garantir que una utilitzacióincorrecta d’un mètode no es pugui produir. Tot i això, es poden donardiverses situacions on s’acabi violant la precondició. En aquest cas, podriaresultar interessant l’ús de les excepcions, tot i que potser no és recomanablefer-ho sempre. També val a dir que les excepcions no tenen perquè utilitzar-senomés en situacions de violació de la pre: també es poden fer servir per avisarde situacions que no la violen però que són d’alguna manera anòmales. Aixídoncs diferenciarem la utilització d’excepcions en dos casos:1. Violació de la Precondició: aquí també hi ha dos casos.(a) Quan la comprovació de la precondició és difícil o costosa, el quefaríem seria canviar la precondició i afegir la gestió de les excepcions ala postcondició, de manera que passaríem a tractar-la com a resultatsespecials (veure cas 2).(b) Si per altra banda, la comprovació de la precondició és fàcil i barata,caldrà diferenciar dues situacions en funció de la utilització de laclasse que estem definint:• Ús local (o privat). No generaríem excepcions ja que es potcontrolar ad-hoc la correcta utilització dels mètodes.• Ús general (o públic). Crearíem excepcions unchecked, donantla possibilitat a l’usuari de la classe a tractar l’excepció o no(recordem que en aquest darrer cas avortaria l’execució). Perexemple, desempilar() d’una pila buida.2. Tractament de resultats especials: en aquest cas generaríem unachecked exception, forçant a l’usuari del mètode a controlar aquestes situacions.En general, la utilització d’aquest mecanisme és millor que retornarun codi especial ja que evita qualsevol confusió amb un possible valor deretorn.Per exemple, en demanar la posició que ocupa un enter dins d’un vectord’enters quan aquest element no hi és. Si no disposéssim d’un mecanismede generació i tractament d’excepcions, podríem fer:// Declaracio del metodeint posicio(int n){// Pre: n pertany a l’estructura...// Post: retorna la posicio de n}...// Comprovacio de precondicio ad-hoc5


if (t.pertany(n)) p = t.posicio(n);else ...Notem que la comprovació és “cara”: costa tant mirar si l’element hi éscom determinar la seva posició. D’altra banda, si fem:// Declaracio del metodeint posicio(int n){// Pre: ---...// Post: retorna la posicio de n,// -1 si n no hi es}...p = t.posicio(n);l’enter retornat podria ser interpretat com una posició vàlida (per algunprogramador que no s’hagués llegit l’especificació) i provocar un error mésendavant.En canvi, emprant el mecanisme de les excepcions, no caldria perdre tempsni “embrutar” el programa fent cap comprovació, i no seria possible obviarla situació excepcional:// Declaracio del metodeint posicio(int n) throws Exception {// Pre: ---...// Post: retorna la posicio de n,// o genera excepcio si no hi es}...// Bloc de temptativa i capturatry{ p = t.posicio(i); }catch(Exception e){ ... }Cal tenir en compte que el compilador ens avisaria que cal emprar el bloctry - catch per tractar la possible excepció, o bé propagar-la.6

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!