Argomenti della lezione
 Interfacce
 Eccezioni
 IO in Java
 Collection
 Esercizio riassuntivo: un’applicazione
1: Java notes
1
Interfacce
 Permette al programmatore di stabilire la
struttura di una classe: nomi dei metodi,
argomenti e tipi restituiti (in una parola i
prototipi dei metodi), ma non i corpi degli
stessi. Può, inoltre, contenere variabili
d’istanza (campi), ma queste sono
implicitamente static e final.
 Un’interfaccia fornisce solo una struttura,
ma non un’implementazione
1: Java notes
2
Interface
 Per creare un’interfaccia si usa la parola
chiave interface al posto di class.
 Come per una classe si può dichiarare
un’interaccia public (solo se definita in un
file con lo stesso nome). Senza
dichiarazione esplicita l’interfaccia sarà
utilizzabile solo all’interno dello stesso
package cui appartiene.
1: Java notes
3
Interfacce, ereditarietà e
polimorfismo
 Mentre in Java una classe può ereditare da una
sola altra classe (sia essa normale od abstract),
essa può però ereditare da più interfacce.
 Tutte le interfacce da cui una classe sta
ereditando vanno scritte separate fra loro da
virgole dopo la parola chiave implements.
 Si può ereditare da quante interfacce si vuole,
ciascuna delle quali diviene un tipo indipendente
verso il quale si può effettuare l’upcasting.
 Se una classe eredita sia da una classe che da una
o più interfacce contemporaneamente, l’elenco di
interfacce deve seguire la classe concreta (in caso
contrario il compilatore da un errore).
1: Java notes
4
Esempio 1/2
 Albero delle
dipendenze
1: Java notes
5
Esempio 2/2
import java.util.*;
interface Instrument {
// Compile-time constant:
int i = 5; // static & final
// Cannot have method definitions:
void play(); // Automatically public
String what();
void adjust(); }
class Wind implements Instrument {
public void play(){
System.out.println("Wind.play()"); }
public String what() { return "Wind"; }
public void adjust() {} }
class Percussion implements Instrument {
public void play(){
System.out.println("Percussion.play()"); }
public String what() { return "Percussion"; }
public void adjust() {} }
class Stringed implements Instrument {
public void play() {
System.out.println("Stringed.play()"); }
public String what() { return "Stringed"; }
public void adjust() {} }
class Brass extends Wind {
public void play() {
System.out.println("Brass.play()"); }
public void adjust() {
System.out.println("Brass.adjust()"); } }
class Woodwind extends Wind {
public void play() {
System.out.println("Woodwind.play()"); }
public String what() { return "Woodwind"; } }
public class Music {
// Doesn't care about type, so new types
// added to the system still work right:
static void tune(Instrument i) {i.play(); }
static void tuneAll(Instrument[] e) {
for(int i = 0; i < e.length; i++) tune(e[i]); }
public static void main(String[] args) {
Instrument[] orchestra = new Instrument[5];
int i = 0;
// Upcasting during addition to the array:
orchestra[i++] = new Wind();
orchestra[i++] = new Percussion();
orchestra[i++] = new Stringed();
orchestra[i++] = new Brass();
orchestra[i++] = new Woodwind();
tuneAll(orchestra); } }
1: Java notes
6
Ancora sull’ereditarietà
 Usando
l’ereditarietà è
posibile aggiungere
nuovi metodi alle
interfacce, così
come è possibile
combinare diverse
interfacce fra loro
in una nuova
interfaccia.
interface Monster { void menace(); }
interface DangerousMonster extends Monster {
void destroy(); }
interface Lethal { void kill(); }
class DragonZilla implements DangerousMonster {
public void menace() {}
public void destroy() {} }
interface Vampire extends DangerousMonster,
Lethal {
void drinkBlood(); }
public class HorrorShow {
static void u(Monster b) { b.menace(); }
static void v(DangerousMonster d) {
d.menace();
d.destroy(); }
public static void main(String[] args) {
DragonZilla if2 = new DragonZilla();
u(if2);
v(if2); }
}
1: Java notes
7
Inoltre
 Ogni campo di un’interfaccia è automaticamente
static e final, quindi l’interfaccia ben si presta alla
realizzazione di gruppi di costanti come, ad
esempio, accade facendo uso di un enum in C o C++.
 I campi di un interfaccia sono automaticmente
public anche se non esplicitamente specificato.
Essendo inoltre static e final, devono essere
inizializzati. I valori di tali campi possono essere
assegnati una volta per tutte, per mezzo di
espressioni non costanti che vengono calcolate
nell’istante della loro creazione.
1: Java notes
8
Esempio
public interface Months {
int JANUARY = 1,
FEBRUARY = 2,
MARCH = 3,
APRIL = 4,
MAY = 5,
JUNE = 6,
JULY = 7,
AUGUST = 8,
SEPTEMBER = 9,
OCTOBER = 10,
NOVEMBER = 11,
DECEMBER = 12;
}
import java.util.*;
public interface RandVals {
int rint = (int)(Math.random()*10);
long rlong = (long)(Math.random()*10);
float rfloat =
(float)(Math.random()*10);
double rdouble = Math.random()*10;
}
public class TestRandVals {
public static void main(String[] args) {
System.out.println(RandVals.rint);
System.out.println(RandVals.rlong);
System.out.println(RandVals.rfloat);
System.out.println(RandVals.rdouble)}
}
1: Java notes
9
Eccezioni
 Un’eccezione è un segnale indicante il verificarsi di
un’errore o di una condizione anomala
nell’esecuzione del programma. Lanciare
un’eccezione significa segnalarne l’occorrenza,
mentre catturarla significa captare il suddetto
segnale e gestire tale eccezione.
 L’eccezione è un’oggetto, istanza della classe (o di
una sottoclasse di) java.lang.Throwable. Esistono
due sue sottoclassi standard di eccezioni in Java:


java.lang.Error –corrispondenti ad errori irrecuperabili
(memoria della JVM esaurita, class-file corrotto).
java.lang.Exception –corrispondono a errori meno gravi e
possono essere catturate e gestite con del codice
adeguato.
1: Java notes
10
Gestire le eccezioni: try - catch
 L’istruzione try identifica un blocco di codice che può
generare eccezioni in modo che queste vengano catturate.
 Uno o più blocchi identificati dall’istruzione catch seguono il
blocco try e contengono il codice per la gestione di un
particolare tipo di eccezione. L’istruzione catch ha un solo
argomento, che specifica la classe a cui appartiene l’oggetto
eccezione che il blocco può gestire.
 Quando viene lanciata un’eccezione, si interrompe
l’esecuzione del codice e si cerca un blocco catch il cui
argomento è un’istanza della stessa classe (o di una
superclasse) dell’eccezione lanciata. Se non esiste nel
metodo corrente, viene cercato nel metodo che ha invocato il
metodo corrente, e cosi’ via a ritroso fino ad arrivare al
metodo main(). Se non vene trovato neanche lì, l’esecuzione
del programma viene terminata con un messaggio d’errore.
1: Java notes
11
Throws e throw
 Un metodo può lanciare un’eccezione, eventualmente creata
dal programmatore, con l’istruzione throw.
 Tutti i metodi Java possono usare la clausola throws per
gestire le eccezioni:
throws lista di sottoclassi della classe Exception che possono
essere lanciate dal metodo
 La clausola throws è aggiunta nell'intestazione della
definizione di un metodo:
public static void main(String[] args) throws Exception {...}
 Alcune eccezioni sono verificate (checked) in compilazione e
devono essere menzionate nella clausola throws di qualunque
metodo che le lancia con un'istruzione throw, oppure le
propaga tramite altri metodi. Le eccezioni non-verificate
(unchecked) sono oggetti del tipo RunTimeException. Non è
richiesto che le sotto classi della classe RunTimeException
vengano menzionate nella clausola throws (da qui unchecked).
1: Java notes
12
Gestione eccezioni parenti
 Attenzione:
se Exception2 è una sottoclasse di Exception1,
si può usare solo un blocco catch relativo a
Exception1: tale blocco gestisce entrambi i tipi
di eccezioni.
 se si vuole gestire le due eccezioni in modo
differente occorre mettere prima il blocco che
gestisce l’eccezione figlia Exception2 e poi
quello che gestisce l’eccezione genitore
Exception1.

1: Java notes
13
Blocco finally
 I blocchi catch possono opzionalmente essere
seguiti da un blocco finally contenente codice di
“pulizia” la cui esecuzione è garantita, qualunque
cosa succeda nel blocco try.
 Appena l’esecuzione lascia il blocco try, prima di
passare altrove, viene eseguito il codice contenuto
nel blocco finally.
 Ogni blocco try deve essere seguito da (almeno) un
blocco catch e/o un blocco finally.
 Ognuno dei blocchi deve iniziare e finire con le
parentesi graffe (anche se composti da una sola
istruzione)
1: Java notes
14
Esempio
public void unMetodo() throws MyException {
Try
{
… (qui é contenuto del codice che può lanciare un’eccezione
di tipo SomeException, oppure un’eccezione di tipo AnotherException)
}
catch(SomeException e1)
{
… (codice che gestisce un’eccezione di tipo SomeException)
}
catch(AnotherException e2)
{
… (codice che gestisce un’eccezione di tipo AnotherException)
}
finally
{
… (codice che viene sempre eseguito, dopo essere usciti per qualsiasi motivo
dal blocco try – tranne nel caso in cui viene invocato il metodo System.exit()
il quale interrompe l’esecuzione dell’interprete Java)
}
if (condizione) throw new MyException(); // questa non viene gestita direttamente dal
// metodo che la sta lanciando
}
1: Java notes
15
IO in Java: Stream
 Stream: canale di





comunicazione tra un
programma (Java) e una
sorgente (destinazione) da cui
importare (verso cui
esportare) dati
L’informazione viene letta
(scritta) serialmente, con
modalità FIFO
Read Only o Write Only:
servono due stream per un
canale bi-direzionale
Bloccante
Quasi tutti i metodi possono
generare eccezioni
Il package java.io contiene
classi che implementano gli
stream
Lettura
Apri lo stream
while (ci sono ancora
dati)
leggi dato
chiudi lo stream
Scrittura
Apri lo stream
while (ci sono ancora
dati)
scrivi dato
chiudi lo stream
1: Java notes
16
Tipi di Stream
 Due gerarchie di classi:
 Stream di caratteri: per
leggere/scrivere caratteri
UNICODE a 16 bit
 Stream di byte: per
leggere/scrivere byte
(tipicamente dati)
1: Java notes
17
Stream di caratteri
 Implementati dalle superclassi abstract Reader e
Writer
 Reader: contiene una parziale implementazione e le
API (metodi e campi) per realizzare stream che
leggono caratteri
 Writer: contiene una parziale implementazione e le
API (metodi e campi) per realizzare stream che
scrivono caratteri
 Sottoclassi di Reader e Writer implementano
stream specializzati
1: Java notes
18
Stream di caratteri/2
 Classi grigie: leggono/scrivono e basta
 Classi bianche: compiono anche qualche tipo di elaborazione
1: Java notes
19
Stream di byte
 Implementati dalle superclassi abstract
InputStream e OutputStream
 InputStream: contiene una parziale
implementazione e le API (metodi e campi) per
realizzare stream che leggono byte
 OutputStream: contiene una parziale
implementazione e le API (metodi e campi) per
realizzare stream che scrivono byte
 Sottoclassi di InputStream e OutputStream
implementano stream specializzati
1: Java notes
20
Stream di byte/2
 Classi grigie: leggono/scrivono e basta
 Classi bianche: compiono anche qualche tipo di elaborazione
1: Java notes
21
Estensioni degli stream - Filtri
 Caratteristiche fondamentali dei filtri:




Sono classi derivate da InputStream e OutputStream
Si attaccano a un InputStream o OutputStream: chiamare
write() su un filtro significa chiamare anche write()
sull’OutputStream attaccato
E’ possibile combinare in serie diversi filtri ottenendo
combinazioni potenti
In pratica, si usano sottoclassi di FilterOutputStream e
FilterInputStream
FilterOutputStream OutputStream
InputStream FilterInputStream
1: Java notes
22
InputStreamReader/
InputStreamWriter
 Sottoclassi di Reader/Writer
 Creano un ponte tra stream a byte e a carattere
 Costruttori:
 public InputStreamReader(InputStream in): accetta un
oggetto InputStream e crea un oggetto
InputStreamReader (e dunque Reader)
 public OutputStreamWriter(OutputStream out): accetta
un oggetto di tipo OutputStream e crea un oggetto di tipo
OutputStreamWriter (e dunque Writer)
 Altri costruttori permettono di specificare una codifica
1: Java notes
23
InputStreamReader/
InputStreamWriter/2
 La codifica permette di associare byte e caratteri
 Esempio: i byte dello stream sottostante possono
rappresentare caratteri codificati in formato UNICODE a 16
bit
char
byte
InputStreamReader
InputStream
(codifica – Es. UN 16 bit)
La situazione è analoga per un OutputStreamWriter
1: Java notes
24
BufferedReader/
BufferedWriter
 Realizzano buffering per rendere più efficienti le
operazioni di I/O su stream di caratteri
 Costruttori:
public BufferedReader(Reader in)
 public BufferedReader(Reader in, int sz)
 public BufferedWriter(Writer out)
 public BufferedWriter(Writer out, int sz)
sz: dimensione del buffer

 Metodo più importante:
 public String readLine() throws IOException: legge una
linea di testo, restituendo la stringa corrispondente
1: Java notes
25
System.in/System.out
I/O standard
 in e out sono membri
(variabili static final)
della classe System
 in è di tipo
InputStream, out di
tipo OutputStream (è
in realtà oggetto di
classe PrintStream,
una sottoclasse di
OutputStream)
import java.io.*;
public class classeLettura {
public static void main(String args[]) throws
IOException {
InputStream stdIn = System.in;
InputStreamReader in = new InputStreamReader(stdIn);
BufferedReader myReader = new BufferedReader(in);
String inputLine;
myReader.readLine();
System.out.println("Hai scritto "+inputLine);
}
}
1: Java notes
26
La gestione dei file in Java
 In Java esiste la classe File che è una




rappresentazione astratta di file e directory
La classe File possiede metodi per manipolare file e
directory, ma non per leggere/scrivere
La lettura/scrittura su/da un file viene effettuata
attraverso l’associazione di uno stream all’oggetto
di classe File
Se il file non esiste, esso è effettivamente creato
solo quando si apre uno stream verso di esso
Costruttore principale:

public File(String pathname) throws NullPointerException
1: Java notes
27
Gli stream di lettura e scrittura
orientati ai byte per file
 FileInputStream/FileOutputStream
 Sono sottoclassi di InputStream e OutputStream che
aprono stream di byte da/verso file.
 Hanno gli stessi metodi di InputStream e OutputStream
 Si possono applicare i filtri (ad esempio DataInputStream
e DataOutputStream)
 Costruttori principali:
• public FileInputStream(File file) throws
FileNotFoundException
• public FileOutputStream(File file) throws
FileNotFoundException
1: Java notes
28
Gli stream di lettura e scrittura
orientati ai caratteri per file
 FileReader/FileWriter:
 Sono sottoclassi di Reader e Writer che aprono stream di
caratteri da/verso file
 Hanno gli stessi metodi di Reader e Writer
 Si possono applicare i filtri (ad esempio BufferedReader e
BufferedWriter)
 Costruttori principali:
• public FileReader(File file) throws FileNotFoundException
• public FileWriter(File file) throws FileNotFoundException
1: Java notes
29
Tenere oggetti: Collection e Map
 Java presenta 2 diverse librerie al fine di
contenere oggetti, basate su due distinti
approcci:
 Collection:
un gruppo di elementi individuali,
soggetti a particolari regole. Ad esempiouna
List deve tenere oggetti in una particolare
sequenza, un Set non può avere elementi
duplicati.
 Map: un gruppo di oggetti chiave-valore.
1: Java notes
30
Tassonomia delle contenitori
1: Java notes
31
Liste, stack e code in Java
 Questi dati sono rappresentati e implementati da
interfacce e classi del package Java.util (in realtà
strutture dati più ricche)
 L’interfaccia più generale è Collection
 Rappresenta un
insieme di elementi,
eventualmente
replicati (multinsieme)
 Ammette operazioni
di inserimento e
cancellazione
1: Java notes
32
Tipo di dato Lista
 Insieme di elementi tra i quali è definito un
ordinamento totale.
 Ammette (almeno) le operazioni seguenti:


insert(elem, i): inserisce elem in posizione i-esima
remove(i): elimina l’i-esimo elemento della lista
 Altre operazioni possibili (non tutte):
 findkth(i): restituisce l’i-esimo elemento
 isEmpty: restituisce vero se la lista è vuota
1: Java notes
33
Liste in Java
 E’ un’interfaccia
 Rappresenta una collezione ordinata di
elementi
 Ammette duplicati
 Implementazioni: classi LinkedList,
ArrayList e Vector
1: Java notes
34
Classe Vector
Array:
 Può contenere solo
oggetti appartenenti
allo stesso tipo di dato
 Dimensione fissa
 Pochi metodi ma
maggiore efficienza
Classe Vector
 Contiene Object. I tipi di
dati primitivi devono
essere convertiti mediante
gli opportuni wrapper.
 Gestione flessibile dello
spazio di memoria.
 Gran numero di metodi a
scapito dell'efficienza
1: Java notes
35
Esempi di utilizzo delle classi Vector ed
Enumeration
Vector v = new Vector();
String st = br.readLine();// br di tipo BufferedReader
while (st != null) {
v.addElement(st);
st = br.readLine();
}
Enumeration e = v.elements();
while (e.hasMoreElements()) {
String s t= (String)e.nextElement();// il metodo nextElement
// restituisce un oggetto di classe Object per cui occorre
// usare l'operatore di cast.
System.out.println(st);
}
1: Java notes
36
Vettore di tipi di dato primitivi
Vector v = new Vector();
String st = br.readLine();// br di tipo BufferedReader
while (st != null) {
int num = Integer.parseInt(st);
v.addElement(new Integer(num));
st = br.readLine();
}
Enumeration e = v.elements ();
while (e.hasMoreElements()) {
Integer I = (Integer)e.nextElement(); // I : oggetto della classe Integer
int i = I.intValue();
// i : variabile del tipo primitivo int
System.out.println(i);
}
1: Java notes
37
Tipo stack
 Lista nella quale inserimenti e cancellazioni avvengono solo in
coda (disciplina LIFO).
 Operazioni:

clear(): elimina tutti gli elementi dalla pila

isEmpty(): verifica se la pila è vuota

isFull(): verifica se la pila è piena

push(el): inserisce l'elemento specificato da el in cima alla pila

pop(): elimina l'elemento in cima alla pila

topEl(): restituisce l'elemento in cima alla pila senza cancellarlo
dalla lista
1: Java notes
38
Implementazione tramite
java.util.Stack
 Java fornisce una classe Stack che
implementa il tipo di dato primitivo stack:

Costruttore:
• Stack Stack(): Crea una pila vuota

Metodi:
• boolean empty(): restituisce true se la pila è vuota
• Object peek(): realizza l'operazione topEl()
• Object pop(): rimuove e restituisce l'elemento
affiorante
• Object push(el): inserisce l'elemento specificato in
cima alla pila
• int search(el):restituisce la posizione di el all'interno
della pila
1: Java notes
39