# Gestió d'excepcions
|**Resultat d'aprenentatge relacionat**|
| -------- |
| Desenvolupa aplicacions que gestionen informació emmagatzemada en fitxers identificant el camp d’aplicació dels mateixos i utilitzant classes específiques. |
|**Contingut relacionat**|
| -------- |
| Preveu i gestiona les excepcions |
#### **Què són les excepcions?**
Les excepcions són els mitjans que ofereixen els llenguatges de programació per tractar situacions anòmales que poden succeir durant l'execució d'un programa, donant lloc a la interrupció del flux normal que aquest programa té.
Un exemple clàssic de situació anòmala és la divisió d'un nombre per zero. Però no és l'única. D'altres ben conegudes són: intentar obrir un fitxer que no existeix o quedar-nos sense memòria a la JVM quan un programa ha entrat en una mena de bucle infinit.
La forma amb la qual s'aborda una excepció (per exemple, aturar l'execució i llençar un missatge) és el que d'ara endavant anomenarem com **gestió de les excepcions**.
#### **Exemple de situació anòmala**
Per il·lustrar una mica millor el que és una situació anòmala, prenem d'exemple una funció que ens retorna el resultat d'una divisió de forma exacta (un nombre enter, sense decimals). El codi podria ser com segueix:
```
public class MainDiv {
public static int Exactdivision (int dividend, int divisor) {
int c = dividend / divisor;
return c;
}
}
```
Un cop definida la funció, anem a executar-la amb unes condicions un tant particulars, com és que el nombre que farà de divisor sigui 0:
```
public class MainDiv {
//Definició de la funció
public static void main (String args[]) {
int a = 10;
int b = 0;
System.out.println("El resultat de la divisió d'"+ a +
" entre " + b + " és: "+ Exactdivision(a, b));
}
}
```
Un cop executat aquest codi obtindrem un missatge com el següent:
```
Exception in thread "main" java.lang.ArithmeticException: /
by zero at MainDiv.Exactdivision(MainDiv.java:5)
at MainDiv.main(MainDiv.java:15)
```
Aquest missatge és la pila corresponent a les crides que s'han fet fins arribar al punt, a la línia, que causa l'error.
#### **Motivació de les excepcions. Per a què (i per a què no) serveixen?**
Cal clarificar que les excepcions són de vital importància en el disseny i implementació de qualsevol codi. Així, dues raons per les quals poden servir les excepcions són:
* Alertar-nos de les situacions anòmales que es poden donar en el nostre codi.
* Permetre'ns decidir com ha de respondre el codi davant d'aquestes situacions.
No obstant, pot dur a confusió pensar que una excepció servirà per corregir situacions inesperades o errors de programació.
Imaginem un programa que espera un fitxer en una ubicació per obrir i llegir-lo i aquest no existeix en aquesta ubicació. Les excepcions no serviran per fer aparèixer com per art de màgia aquest fitxer.
Un altre exemple que segurament en algun cop heu vist és fer referència a una posició (índex) que es troba fora d'un array. Les excepcions tampoc faran que aquesta ocurrència dins l'array de cop existeixi.
Per tant, en totes dues situacions les excepcions ens alertaran del que està passant. I ja serà decisió del programador quin és el tractament a donar quan succeeixin.
#### **Throwable, error i exception**
**Throwable** és una classe base que representa tots aquells objectes que es poden llençar o capturar, de tal forma que:
* Ens informa de l'estat de la pila en el moment en el qual es crea l'objecte (stack trace).
* Emmagatzema un missatge (un String) el qual conté detall de l'error produït.
* Pot tenir una causa que permet representar l'error original, el que dona lloc a l'error que observem.

*Font de la imatge: https://ocw.mit.edu/ans7870/6/6.005/s16/classes/06-specifications/exceptions/*
**Error** és una subclasse de Throwable la qual ens mostra errors greus, produïts pel Java Runtime System.
Per últim, **Exception** (i subclasses d'aquesta) indica situacions les quals l'aplicació hauria de ser capaç de gestionar de forma raonable. Un exemple són els RuntimeException típics de la divisió per zero, que apuntem a un índex d'un array fora dels seus límits, etc.
#### **LLençament d'excepcions amb throw.**
Utilitzarem el throw per llençar objectes del tipus throwable. En altres paraules, per poder llençar excepcions "customitzades".
És important no confondre-la amb el throws() ja que la seva funció i propòsit són completament diferents.
Vegem el següent exemple d'ús del throw():
```
public class PotsVotar {
public static void comprovarEdat(int edat) {
if (edat < 18) {
throw new ArithmeticException("No pots votar");
} else {
System.out.println("Pots votar");
}
}
}
```
El que estem fent és dir que si no es compleix la condició d'edat, es creï una instància d'ArithmeticException.
#### **La clausula Throws.**
Throws és una paraula clau utilitzada a la declaració d'un mètode i serveix per indicar que aquest mètode pot potencialment llençar una sèrie d'excepcions.
Així quan aquest mètode és cridat, el mètode que el crida ha de ser capaç de capturar i gestionar les excepcions que hi pugui llençar.
Si prenem de nou l'exemple del mètode Exactdivision, acabem de veure que si el divisor és 0 es produirà una excepció. El que podem fer és incorporar el throws a la declaració del mètode d'aquesta forma:
```
public static int Exactdivision (int dividend, int divisor)
throws Exception {
int c;
if (divisor != 0) {
c = dividend / divisor;
} else {
throw new Exception();
}
return c;
}
```
Fixeu-vos com fem servir el throw per poder forçar el llençament de l'excepció que possiblement ocurreixi.
#### **Captura d'excepcions. Blocs try-catch.**
Una forma per poder capturar i gestionar adientment les excepcions és fent servir els blocs try-catch-finally.
El que faríem es introduir aquests blocs en el cos de aquelles funcions que poden donar lloc a situacions excepcionals. De forma esquemàtica ho faríem com segueix:
```
try {
Fiquem aquí el codi que pot generar excepcions
} catch (excepció1 ex1) {
Indiquem aquí que fer per la primera excepció capturada
} catch (excepció2 ex2) {
Indiquem aquí que fer per la segona excepció
(si n'hagués més d'una) capturada
} ...
```
Fixem-nos que la clausula catch rep com argument un objecte *Throwable* que són les excepcions 1, 2, etc. pròpiament dites.
Després del darrer bloc catch i de forma opcional es pot afegir un bloc finally que sempre s'executarà independentment a si hi ha hagut o no error. Un exemple com veurem més endavant es podria correspondre a tancar un fitxer obert o a alliberar recursos en cas d'excepció.
Prenent d'exemple el codi inicial de la divisió, el podriem reescriure d'aquesta forma:
```
public class MainDiv {
public static void main (String args[]) {
int a = 10;
int b = 0;
try {
System.out.println("El resultat és: "
+ Exactdivision(a, b));
} catch (ArithmeticException e1) {
System.err.println ("toString => " + e1.toString());
System.err.println ("getMessage => " + e1.getMessage());
e1.printStackTrace();
}
}
}
```
El resultat un cop s'executa el codi amb aquesta incorporació del try-catch seria:
```
toString => java.lang.ArithmeticException: / by zero
getMessage => / by zero
java.lang.ArithmeticException: / by zero
at MainDiv.Exactdivision(MainDiv.java:9)
at MainDiv.main(MainDiv.java:25)
El resultat és: 0
```
Tot seguit, parem un moment l'atenció en els mètodes que hem fet servir dins el catch de l'excepció:
* **excepció.toString()** >> Retorna una breu descripció de l'objecte. En el cas de l'exemple es correspon amb l'output *"java.lang.ArithmeticException: / by zero"*
* **excepció.getMessage()** >> Retorna la cadena d'error de l'objecte. En el cas de l'exemple es correspon amb l'output *"/ by zero"*.
* **excepcio.printStackTrace()** >> És un void que mostra la pila de crides llençada, a més de visualitzar l'objecte. En el cas de l'exemple es correspon amb l'output "*java.lang.ArithmeticException: / by zero
at MainDiv.Exactdivision(MainDiv.java:9)
at MainDiv.main(MainDiv.java:25)*"
Aquests mètodes ens permetran alertar que s'està produint l'excepció. Però no faran res més. És el programador qui ha de decidir que fer, bé incorporant codi al finally o bé prenent altres tipus de mesures i/o validacions prèvies a accedir a la funció.
Sense ànim d'estendre'ns més i per finalitzar direm que es poden niuar diferents blocs try. És a dir:
```
try {
try {
...
}
} catch (excep e1) {
}
```
En cas que un dels blocs try niuats no disposi d'un bloc catch corresponent, l'excepció es gestionarà pel següent catch extern. Prenent l'exemple anterior, l'excepció es gestionarà pel catch (excep e1).
#### **Exercicis proposats**
1. Reescriviu el mètode PotsVotar() fent ús del throws a la declaració.
2. Quina excepció podria donar el següent codi?
String [] array_string = new String [25];
System.out.println(array_string[3].length());
3. Observa el següent codi i digues que succeirà quan s'executi:
String aux = "adeu";
int aux2 = Integer.parseInt(aux);
#### **Referències i Bibliografia**
1. https://elvex.ugr.es/decsai/java/pdf/B2-excepciones.pdf
2. https://ocw.mit.edu/ans7870/6/6.005/s16/classes/06-specifications/exceptions/
3. https://www.javaguides.net/2018/08/java-exception-handling-guide.html