LIP: 4 Aprile 2008
ECCEZIONI
Eccezioni
• Come si definiscono eccezioni
• Come si lanciano
• Come si gestiscono (gestione esplicita o di
default)
Eccezioni in Java
• Un programma Java puo’
1) terminare normalmente
2) terminare in modo eccezionale
(l’interprete segnala l’eccezione
indicandone il tipo)
Esempio:riferimento null
public class NestedNullPointer {
public static void bar(){
Object o = null;
System.out.println(o.toString());
}
public static void foo(){
bar();
}
public static void main(String [] args){
foo();
}
}
Esecuzione del main
 java java
• Tutti i metodi annidati terminano
• Viene elencata la catena dei metodi attivi nel momento in
cui si verifica l'eccezione (bar - foo - main) e per ogni
metodo la linea di codice dove si è verificata
• In questo caso l’eccezione NullPointer (primitiva) segnala
un errore run-time, ovvero una chiamata di un metodo su
un oggetto null
Le eccezioni in Java
• i tipi di eccezione sono particolari classi che
– contengono solo il costruttore
• ci possono essere più costruttori overloaded
• le eccezioni sono oggetti
– creati eseguendo new di un exception type
• e quindi eseguendo il relativo costruttore
• esiste una gerarchia “predefinita” di tipi relativi
alle eccezioni
– nuovi tipi di eccezioni sono collocati nella gerarchia
con l’usuale extends
La gerarchia di tipi per le
eccezioni
Throwable
Error
Exception
RuntimeException
• se un nuovo tipo di eccezione estende la classe
Exception
– l’eccezione è checked
• se un nuovo tipo di eccezione estende la classe
RuntimeException
– l’eccezione è unchecked
Differenza: checked e unchecked
• se una procedura può sollevare una eccezione
checked (controllata)
– deve elencarla nel suo header (tramite throws)
• altrimenti si verifica un errore a tempo di
compilazione
• se una procedura può sollevare una eccezione
unchecked (runt-time)
– può non elencarla nel suo header
Eccezioni Primitive: run-time
– IndexOutOfBoundsException
– NullPointerException
– I metodi foo, bar e main possono terminare lanciando
questa eccezione
-- non e’ obbligatorio riportarla nell’intestazione
del metodo
Eccezione Controllata
public class NotFoundException
extends Exception {
//costruttore
public NotFoundException(String s)
{super(s);}
}
•
•
•
•
la stringa contenuta nell’eccezione
permette all’utente di identificare la procedura che la ha sollevata
può comparire nel messaggio di errore che si stampa subito prima di forzare la
terminazione dell’esecuzione
si puo’ anche mettere un costruttore senza argomenti
Lanciare eccezioni
• Una eccezione si lancia tramite il costrutto throw
throw new NotFoundException(“nome metodo corrente”);
• La new crea l’eccezione contenente la stringa
• Il metodo corrente si sospende e passa il controllo
al chiamante
Gestione delle Eccezioni
Il chiamante puo’
– gestione di default, mediante propagazione dell’eccezione alla procedura
chiamante
• possibile solo per eccezioni non checked o per eccezioni checked
elencate nell’header della procedura che riceve l’eccezione
– gestione esplicita (mediante try and catch), cattura e gestisce l’eccezione
Catturare una Eccezione
• Il codice che potrebbe sollevare l’eccezione e’ racchiuso
all’interno di uno statement try
• Il codice per gestire l’eccezione e’ racchiuso all’interno di
uno statement catch
• In realta’ possono esserci vari statements catch per
catturare diverse eccezioni e gestirle in modo
specifico (vedi documentazione Java)
Esempio
public static boolean cerca(int[] a, int x) throws
NotFoundException{
\\EFFECTS: se x occorre in a restituisce true,
\\ altrimenti solleva l’eccezione NotFound
for (int i=0; i<a.length,i++)
if (a[i]==x) {return true;}
throw new NotFoundException(“cerca”);
}
• Il metodo chiamante deve gestirla in modo esplicito o per
default
• NotFoundException e’ controllata (se un metodo puo’
sollevarla deve essere elencata nella sua intestazione)
Gestione Default
public static void usa-cerca()
throws NotFoundException{
.......cerca(b,8);
}
• Se cerca(b,8 ) termina lanciando NotFound il metodo termina
lanciando NotFound
• Dato che l’eccezione e’ controllata deve essere elencata
nell’intestazione
Gestione Esplicita
public static void usa-cerca() {
.......try{cerca(b,8)}
catch (NotFoundException e)
{....codice che gestisce e...};
}
• Se cerca(b,8 ) termina lanciando NotFound il metodo esegue
....codice che gestisce e....
Esempio
• Esempio: pila (Stack) di interi
• Mantiene gli elementi per ordine di
inserimento (LIFO)
• E’ utile utilizzare le eccezioni per
segnalare alcuni casi particolari o situazioni
non richieste
Quali operazioni?
• isEmpty() serve per testare se la pila e’
vuota
• top() serve per leggere l’elemento al top della
pila, ovvero l’ultimo inserito
• pop() rimuove l’ultimo elemento inserito (al
top della pila)
• push (int x) inserisce x nella pila al top
PRECONDIZIONI: top()
non sia vuota
e pop() per garantire che
Modifica della Specifica
• Si possono rimuovere le precondizioni,
trasformando i metodi da parziali a totali
• Usando un’eccezione EmptyException
(controllata) per segnalare il fatto che c’e’
un errore
• Omettiamo la def. Del tipo eccezione
(standard)
Specifica e implementazione
public class Stack {
\\ OVERVIEW: uno Stack e’ una collezione di interi organizzati per ordine di
inserimento con una politica LIFO. E’ modificabile
private Vector pila;
public Stack () {
\\ EFFECTS: costruisce uno Stack Vuoto
pila=new Vector();}
public boolean isEmpty() {
\\ EFFECTS: se this e’ vuoto restituisce true, altrimenti false
if (pila.size()==0) {return true;}
else {return false;}
}
Specifica e implementazione
public int top()throws EmptyException {
\\ EFFECTS: se this e’ vuota solleva EmptyException, altrimenti restituisce
l’ultimo elemento inserito
if (isEmpty()) {throws new EmptyException(“Stack.top”);}
Integer x=pila.elementAt(pila.size()-1));
return x.intValue();}
public void pop() throws EmptyException {
\\ MODIFIES: this
\\ EFFECTS: se this e’ vuota solleva EmptyException, altrimenti rimuove
l’ultimo elemento inserito
if (isEmpty()) {throws new EmptyException(“Stack.pop”);}
pila.removeElementAt(pila.size()-1));}
public void push (int x) {
\\ MODIFIES: this
\\ EFFECTS: inserisce x nella pila
pila.addElement(new Integer(x));}
}
Gestione delle Eccezioni
• Chi usa il tipo di dato Stack deve gestire le
eccezioni
• Esempio: procedura stand-alone che
rimpiazza gli elemnenti della pila con la
loro somma
public static void sum (Stack p) throws EmptyException {
\\REQUIRES: p non e’ null
\\MODIFIES: p
\\EFFECTS: se p e’ vuota solleva EmptyException, altrimenti rimuove tutti gli
elementi ed inserisce al top la loro somma
int somma=p.top();
p.pop();
try
{while (true)
{somma = somma+p.top();
p.pop();}
}catch(EmptyException e)
{p.push(somma);}
}
Notate che non accede alla variabile pila di tipo Vector, usa solo l’interfaccia
pubblica!
L’eccezione controllata EmptyException viene propagata automaticamente
al metodo chiamante (deve essere riportata nella clausola throws)
Esercizio I
• Definire una classe Frame che definisce
oggetti che rappresentano funzioni parziali
(a dominio finito) da String (dominio) ad int
(Codominio)
• In sostanza sono delle tabelle (senza
duplicati)
(a,1) (c,14) (b,10)
(c-13) (a,1)(a,6)
non e’ un Frame!
Esercizio I
• Il tipo di dato e’ modificabile
• Vogliamo un ordinamento in base al
primo elemento (String)
(a,1) (b,10) (c,14)
Esercizio I
• Vogliamo le seguenti operazioni (al solito
espresse da costruttori e metodi pubblici)
-leggere il valore associato ad una certa
stringa
-inserire una nuova associazione
-modificare l’associazione esistente per una certa stringa
Esercizio I
• Diamo la specifica in modo da soddisfare le
richieste
• Le proprieta’ devono valere per costruzione
• Usiamo le eccezioni per segnalare i casi non
richiesti
Esercizio: Eccezioni
– NullPointerException e’ una eccezione unchecked
primitiva
– DuplicateException e’ una eccezione checked (da
definire)
– NotFoundException e’ una eccezione checked (da
definire)
Specifica (Interfaccia Pubblica)
public class Frame{
\\ OVERVIEW: un Frame e’ una funzione parziale da stringhe ad
\\ interi. I valori del dominio sono ordinati. E’
\\modificabile
public Frame(){
\\ EFFECTS: costruisce un nuovo Frame indefinito per tutti
\\i valori }
public boolean defined(String s) {
\\EFFECTS: se s e’ null solleva NullPointerException, se this
e’ definita per s restituisce true, altrimenti restituisce
false}
Altri Metodi
public int apply(String s) throws NotFoundException{
\\ EFFECTS: se s e’ null solleva NullPointerException, se this e’
\\ definita per s restituisce il valore associato, altrimenti solleva
\\ NotFoundException}
public String toString(){
\\ EFFECTS: restituisce una stringa che contiene le coppie di this,
\\(x,y) dove y e’ l’elemento associato ad x}
public void bind(String s, int x) throws DuplicateException{
\\MODIFIES: this
\\EFFECTS: se s o x e’ null solleva NullPointerException, se this e’
\\definita per s solleva DuplicateException, altrimenti modifica
\\this aggiungendo l’associazione tra s ed x in base
\\all’ordinamento}
Come si puo’ implementare
Frame?
• La scelta fondamentale (come per tutte le
classi che definiscono oggetti) e’ quella
delle variabili d’istanza
• Definiscono lo stato degli oggetti
• Vanno dichiarate nella classe
• Inizializzate dal costruttore
Per esempio
• Dobbiamo di fatto memorizzare l’insieme delle coppie
(valore dominio, valore codominio)
• Si puo’ usare un Vector che contiene coppie (String, int)
(va definito un tipo coppia)
• Si possono usare due Vector che
memorizzano uno il dominio e l’altro il codominio,
mantenendo nella stessa posizione gli elementi associati
• La scelta tra le due implementazioni deve essere invisibile
al di fuori della classe Frame (e.g. a chi lo usa)
A tale proposito
• Notate che la specifica data e’ astratta (non fa riferimento
all’implementazione)
• Al contrario e’ progettata per astrarre dai dettagli della
possibile implementazione
Tipo record Pair
public class Pair{
public String left;
public int right;
public Pair(String s, int i)
{left=s;right=i;}
}
Esercizio II
• Estendere la specifica e l’implementazione
con due nuovi metodi
---union che modifica this, realizzando
l’unione con un Frame f (parametro)
---intersection che modifica this,
realizzando l’intersezione con un Frame f
(parametro)
Attenzione
• L’unione e l’intersezione devono garantire
le proprieta’ richieste
--funzione & ordinamento
• Problema: [ (a,20),(c,1)] unione [(a,3)]
[(a,3),(a,20),(c,1)] non e’ un frame
Di conseguenza
• Bisogna trattare le situazioni non volute
• Tipicamente usando delle eccezioni
Sviluppare (in parallelo) un
Tester
• Costruire un Frame vuoto
• Prendere dei valori da console ed inserire delle
relative associazioni (usando bind)
• Testare sul Frame i metodi apply e defined
• Bisogna testare anche le eccezioni che questi
metodi possono sollevare (bind e apply)
Cosa vuol dire?
• Provare apply su un valore che non e’ definito (il
metodo deve sollevare l’eccezione
NotFoundexception)
• Provare bind su un valore che e’ gia’ definito (il
metodo deve sollevare l’eccezione
Duplicateexception)
• Attenzione a catturare le Eccezioni e non fare
fallire il main (mediante try e catch)
• Fare invece stampare il motivo dell’eccezione
(con toString)
Scarica

Lucidi