Esercitazioni Ingegneria del So2ware 3 - Programmazione Java Excep<ons, I/O Giordano Tamburrelli tamburrelli@elet.polimi.it hhp://giordano.webfac<onal.com 1
Richiamo di teoria: An excep%on is an event, which occurs during the execu<on of a program, that disrupts the normal flow of the program's instruc<ons. 2
Tipi di eccezioni Checked: devono essere ges<te» O catchate» O rilanciate esplicitamente Unchecked: Error rappresentano situazioni eccezionali esterne all applicazione, che è difficile prevedere e risolvere. Sono sohoclassi di Error Non devono essere ges<te necessariamente Run<me Excep<ons rappresentano situazioni eccezionali, interne all applicazione, che difficilmente si possono prevedere o risolvere Sono sohoclassi di Run<meExcep<on Non devono essere necessariamente ges<te 3
Esercizio: Cosa stampa? public static void f() throws Exception{ System.out.println("Throw new Exception in f()"); throw new Exception("Generated in f()"); public static void g() throws Exception{ try { f(); catch (Exception ex) { System.out.println("Exception catched in g(). Rethrow"); throw ex; public static void main(string[] args){ try { g(); catch (Exception ex) { System.out.println("Exception catched in main(). Just stay"); System.out.println(ex.getMessage()); Stampa: Throw new Excep<on in f() Excep<on catched in g(). Rethrow Excep<on catched in main(). Just stay Generated in f() 4
Esercizio: Cosa stampa? public static void f() throws Exception { System.out.println("Throw new Exception in f()"); throw new Exception("Generated in f()"); public static void g() throws Exception { try { f(); catch (Exception ex) { System.out.println("Exception catched in g(). Rethrow"); throw new Exception("Generated in g()"); public static void main(string[] args) { try { g(); catch (Exception ex) { System.out.println("Exception catched in main(). Just stay"); System.out.println(ex.getMessage()); Stampa: Throw new Excep<on in f() Excep<on catched in g(). Rethrow Excep<on catched in main(). Just stay Generated in g() 5
Esercizio: Cosa stampa? public static void f() throws Exception { System.out.println("Throw new Exception in f()"); throw new Exception("Generated in f()"); Stampa: Throw new Excep<on in f() Excep<on catched in g(). Rethrow Excep<on catched in main(). Just stay Generated in g() public static void g() throws Exception { try { f(); catch (Exception ex) { System.out.println("Exception catched in g(). Rethrow"); Exception newe= new Exception("Generated in g()",ex); throw newe; public static void main(string[] args) { try { g(); catch (Exception ex) { System.out.println("Exception catched in main(). Just stay"); System.out.println(ex.getMessage()); Genero una nuova eccezione e specifico la causa che la ha generata. TuHavia in questo esempio non l ho poi usata. 6
Esercizio: Cosa stampa? public static void f() throws Exception { System.out.println("Throw new Exception in f()"); throw new Exception("Generated in f()"); public static void g() throws Exception { try { f(); catch (Exception ex) { System.out.println("Exception catched in g(). Rethrow"); Exception newe= new Exception("Generated in g()",ex); throw newe; Stampa: Throw new Excep<on in f() Excep<on catched in g(). Rethrow Excep<on catched in main(). Just stay Generated in g() Causa: Generated in f(); public static void main(string[] args) { try { g(); catch (Exception ex) { System.out.println("Exception catched in main(). Just stay"); System.out.println(ex.getMessage()); System.out.println("Causa: " +ex.getcause().getmessage()); Adesso stampo il messaggio rela<vo alla causa che ha generato l eccezione in g() 7
Esercizio: Cosa stampa? public static void f() throws Exception { System.out.println("Throw new Exception in f()"); throw new MyException("Generated in f()"); public static void g() throws Exception { try { f(); catch (Exception ex) { System.out.println("Exception catched in g(). Rethrow"); throw ex; catch (MyException ex) { System.out.println("MyException catched in g(). Rethrow"); throw ex; public static void main(string[] args) { try { g(); catch (Exception ex) { System.out.println("Exception catched in main(). Just stay"); System.out.println(ex.getMessage()); class MyException extends Exception{ MyException(String msg){ super("this is an instance of MyException. Message: " +msg); Errore a compile <me. L ordine con il quale cahuriamo le eccezioni è importante. La prima eccezione che è super- <po di quella lanciata verrà eseguito, gli altri ignora<. Il catch di MyExcep<on va spostato sopra 8
Esercizio: Cosa stampa? public static void f() throws Exception { System.out.println("Throw new Exception in f()"); throw new MyException("Generated in f()"); public static void g() throws Exception { try { f(); catch (MyException ex) { System.out.println("MyException catched in g(). Rethrow"); throw ex; catch (Exception ex) { System.out.println("Exception catched in g(). Rethrow"); throw ex; public static void main(string[] args) { try { g(); catch (Exception ex) { System.out.println("Exception catched in main(). Just stay"); System.out.println(ex.getMessage()); class MyException extends Exception{ MyException(String msg){ super("this is an instance of MyException. Message: " +msg); Stampa: Throw new Excep<on in f() MyExcep<on catched in g(). Rethrow Excep<on catched in main(). Just stay This is an instance of MyExcep<on. Message: Generated in f() 9
Esercizio: Vogliamo modellizzare un sistema di 3 Robot per la preparazione di RiceHe. Il sistema è composto da 1 Dispensa 1 RiceHa 1 Robot Cuoco 1 Robot per la spesa 1 Robot per l assaggio Il robot cuoco cerca gli ingredien< nella dispensa. Se tui gli ingredien< sono presen< in cucina, la riceha viene preparata e conseguentemente gli ingredien< consuma<. La cohura può fallire. Il robot per la dispensa è in grado di comprare gli ingredien< e inserirli in dispensa. Il robot per l assaggio assaggia un determinato piaho, se il piaho non è buono il robot cuoco lo prepara nuovamente. Vediamo prima il sistema senza eccezioni. 10
Main senza alcuna ges<one public static void main(){ ArrayList dispensa=new ArrayList(); dispensa.add(new Ingrediente("Sugo",1)); dispensa.add(new Ingrediente("Basilico",1)); dispensa.add(new Ingrediente("Sale",0)); ArrayList ricetta=new ArrayList(); ricetta.add(new Ingrediente("Sugo",2)); ricetta.add(new Ingrediente("Basilico",1)); ricetta.add(new Ingrediente("Sale",1)); RobotCuoco cuoco=new RobotCuoco(); RobotSpesa spesatore=new RobotSpesa(); RobotAssaggiatore assaggiatore=new RobotAssaggiatore(); Piatto p=cuoco.cucina(ricetta, dispensa); assaggiatore.assaggia(p); 11
La struhura delle classi class Piatto{ class Robot{ class RobotCuoco extends Robot{ public Piatto cucina(arraylist ricetta, ArrayList dispensa){... class RobotSpesa extends Robot{ public void spesa(arraylist dispensa, Ingrediente chemanca){... class RobotAssaggiatore extends Robot{ class Ingrediente{ int quantità; String nome; public Ingrediente(String nome, int quantità){ this.nome=nome; this.quantità=quantità; public boolean equals(object o){ return ((Ingrediente)o).nome.equals(this.no me); public void assaggia(piatto p){... 12
Come ges<amo le eccezioni? public Piatto cucina(arraylist ricetta, ArrayList dispensa){ for(int i=0; i<ricetta.size(); i++ ){ Ingrediente IngrRicetta=((Ingrediente)ricetta.get(i)); if(!dispensa.contains(ingrricetta)) ;//manca un Ingrediente Ingrediente IngrInDispensa=(Ingrediente)dispensa.get(dispensa.indexOf(IngrRicetta)); if(ingrindispensa.quantità<ingrricetta.quantità) ; //la quantità dell'ingrediente non è sufficente //tutti gli ingradienti sono presenti cucino for(int i=0; i<ricetta.size(); i++ ){ Ingrediente IngrRicetta=((Ingrediente)ricetta.get(i)); Ingrediente IngrInDispensa=(Ingrediente)dispensa.get(dispensa.indexOf(IngrRicetta)); IngrInDispensa.quantità--; //la cottura può fallire Random r=new Random(18); if(r.nextint(3)<1) ; //cottura fallita //Cottura riuscita return new Piatto(); 13
Soluzione public Piatto cucina(arraylist ricetta, ArrayList dispensa) throws MancaIngredienteException { Random r = new Random(18); do { for (int i = 0; i < ricetta.size(); i++) { Ingrediente IngrRicetta = ((Ingrediente) ricetta.get(i)); if (!dispensa.contains(ingrricetta)) { throw new MancaIngredienteException(IngrRicetta); Ingrediente IngrInDispensa = (Ingrediente) dispensa.get(dispensa.indexof(ingrricetta)); if (IngrInDispensa.quantità < IngrRicetta.quantità) { throw new MancaIngredienteException(IngrRicetta); //tutti gli ingradienti sono presenti //cucino... for (int i = 0; i < ricetta.size(); i++) { Ingrediente IngrRicetta = ((Ingrediente) ricetta.get(i)); Ingrediente IngrInDispensa = (Ingrediente) dispensa.get(dispensa.indexof(ingrricetta)); IngrInDispensa.quantità--; while (r.nextint(3) < 1); //se la cottura fallisce ricucino //Cottura riuscita return new Piatto(); 14
Soluzione class MancaIngredienteException extends Exception { Ingrediente i; MancaIngredienteException(Ingrediente i) { this.i = i; Nel main try { System.out.println("Cucino"); p = cuoco.cucina(ricetta, dispensa); catch (MancaIngredienteException ex) { System.out.println("Faccio la spesa"); spesatore.spesa(dispensa, ex.i); 15
Come ges<amo le eccezioni? class RobotAssaggiatore extends Robot{ public void assaggia(piatto p){ //Non modellizzo l'assaggio del piatto, quindi //la variabile p resta inutilizzata Random r=new Random(System.currentTimeMillis()); try { Thread.sleep(1000); catch (InterruptedException ex) { //nada... if(r.nextint(6)>1) ; //il piatto non mi è piaciuto else ; //il piatto mi è piaciuto 16
Soluzione class RobotAssaggiatore extends Robot{ public boolean assaggia(piatto p){ //Non modellizzo l'assaggio del piatto, quindi //la variabile p resta inutilizzata Random r=new Random(System.currentTimeMillis()); try { Thread.sleep(1000); catch (InterruptedException ex) { //nada... if (r.nextint(6) > 1) return false; //il piatto non mi è piaciuto else return true; //il piatto mi è piaciuto 17
Il main finale Piatto p = null; boolean mipiace=false; do { try { System.out.println("Cucino"); p = cuoco.cucina(ricetta, dispensa); catch (MancaIngredienteException ex) { System.out.println("Faccio la spesa"); spesatore.spesa(dispensa, ex.i); mipiace=assaggiatore.assaggia(p); if(mipiace==false) System.out.println("Non mi piace..."); while(mipiace==false); System.out.println("Mi piace!"); 18
L esercizio sui Robot da cucina mostra come sia possibile ges<re le situazioni di errore in maniera differente. A seconda del contesto e dal <po di errore si può scegliere di Usare il meccanismo di eccezioni di Java In par<colare le eccezioni sono molto u<li in quanto oggei complessi che possono riportare informazioni per il recovery dell errore (nell esempio, l Ingrediente mancante) Usare il valore di ritorno per ges<re l errore nel chiamante Questo caso presuppone che il nostro valore di ritorno non sia già usato per altri scopi. Risolvere la situazione internamente al metodo Se l errore è confinato e si verifica solamente all interno del metodo che s<amo eseguendo (nell esempio, cucina()), probabilmente non è necessario creare un eccezione. 19
Java I/O I flussi rappresentano una sequenza di da< Si può usare un Input Stream per leggere da< Si può usare un Output Stream per scrivere i da< 20
Java: I/O TuHe le classi discendono da InputStream e OutputStream. Ogni sohoclasse permehe di ges<re sorgen< da< di <po differente. InputStream OutputStream FIlterInputStream FIleInputStream ObjectInputStream FIlterOutputStream FIleOutputStream ObjectOutputStream BufferedInputStream DataInputStream BufferedOutputStream DataOutputStream Quella presentata è solo una piccola parte delle classi disponibili, per dehagli vedere la Java documenta<on 21
Java: I/O Esercizio: Copiare due file disinteressandosi del loro contenuto public void copia(string src, String dest) throws IOException { InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest); int c; while ((c = in.read())!= -1) out.write(c); in.close(); out.close(); 22
Java: I/O Esercizio: Copiare due file disinteressandosi del loro contenuto (soluzione alterna<va) public void copia(string src, String dest) throws IOException { Runtime.getRuntime().exec("cp " + src + " " + dest); Ogni applicazione Java possiede una instanza singola della classe Run<me che permehe alle applicazioni Java di andarsi a interfacciare con l environment nel quale l applicazione sta girando. In questo caso abbiamo lanciato la nostra applicazione da una shell unix, quindi possiamo interagire con la shell ed eseguire dei comandi come cp. 23
Java: I/O Esercizio: Copiare il contenuto di un file di testo sorgente in un file di testo di des<nazione, carahere per carahere. public void copia(string src, String dest) throws IOException{ InputStream in = new DataInputStream(new FileInputStream(src)); OutputStream out = new DataOutputStream(new FileOutputStream(dest)); int c; while ((c = in.read())!= -1) { out.write(c); in.close(); out.close(); In questo caso non ho nessun vantaggio. Con<nuo a usare il metodo read() il quale avrà la stessa iden<ca implementazione di InputStream. 24
Java: I/O Esercizio: Copiare il contenuto di un file di testo sorgente in un file di testo di des<nazione, carahere per carahere. (migliorato) public void copia(string src, String dest) throws IOException{ DataInputStream in = new DataInputStream(new FileInputStream(src)); DataOutputStream out = new DataOutputStream(new FileOutputStream(dest)); try{ while(true){ int c = in.readchar(); out.writechar(c); catch(eofexception e){ System.out.println("End of file"); in.close(); out.close(); readchar() è un metodo offerto da DataInputStream. E presente un metodo readxxx per ogni <po primi<vo di Java. RispeHo a prima è cambiato il contraho per il <po di ritorno. Adesso dobbiamo ges<re esplicitamente la fine dello stream 25
Java: I/O Esercizio: Copiare il contenuto di un file di testo sorgente in un file di testo di des<nazione, carahere per carahere. (soluzione alterna<va) public void copia(string src, String dest) throws IOException{ DataInputStream in = new DataInputStream(new FileInputStream(src)); DataOutputStream out = new DataOutputStream(new FileOutputStream(dest)); while(in.available()>0){ int c = in.readchar(); out.writechar(c); in.close(); out.close(); available() ritorna leheralmente il numero di bytes che è possibile leggere dall input stream senza bloccarsi. Per i file funziona tuho, ma per stream differen< potrebbe non coincidere con la fine del file. In quel caso consultare la javadoc. 26
Java: I/O Esercizio: Creare un metodo che preso in ingresso un file di output, scrive dentro il file tuho quello che viene digitato dall utente su terminale fino al carahere #. public void writeondest(string dest) throws IOException { DataInputStream in = new DataInputStream(System.in); DataOutputStream out = new DataOutputStream(new FileOutputStream(dest)); char c; while ((c = in.readchar())!= '#') { out.writechar(c); in.close(); out.close(); Non funziona Il programma non riconosce il carahere #... 27
Java: I/O You might expect the Standard Streams to be character streams, but, for historical reasons, they are byte streams. System.out and System.err are defined as PrintStream objects. Although it is technically a byte stream, PrintStream u<lizes an internal character stream object to emulate many of the features of character streams. By contrast, System.in is a byte stream with no character stream features. To use Standard Input as a character stream, wrap System.in in InputStreamReader. InputStreamReader cin = new InputStreamReader(System.in); 28
Java: I/O Esercizio: Creare un metodo che preso in ingresso un file di output, scrive dentro il file tuho quello che viene digitato dall utente su terminale fino al carahere # public void writeondest(string dest) throws IOException { InputStreamReader in = new InputStreamReader(System.in); OutputStreamWriter out = new OutputStreamWriter( new FileOutputStream(dest)); int c; while ((c = in.read())!= '#') { out.write(c); in.close(); out.close(); 29
Java: I/O Le classi Reader e Writer sono delle classi speciali per ges<re l I/O in Java. Mediante delle opportune funzionalità aggiun<ve possono anche ges<re l internazionalizzazione dell applicazione. Non sono degli stream, ma u4lizzano al loro interno gli stream. Reader Writer.. BufferedReader InputStreamReader BufferedWriter InputStreamWriter FileReader FileWriter 30
Java: I/O Le classi Reader e Writer sono state introdohe con la JDK1.1 appositamente per ges<re i caraheri. Per maggiori info: hhp://java.sun.com/developer/technicalar<cles/streams/ ProgIOStreams/ La Java I/O library ha subito un ulteriore modifica con l introduzione di java.nio. L obieivo di questa libreria è lo speed up dell input/output Per maggiori info: hhp://download.oracle.com/javase/1.4.2/docs/guide/nio/ index.html 31
Java: I/O Esercizio: Cosa succede se il file src non esiste? public void copia(string src, String dest) throws IOException { InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest); int c; while ((c = in.read())!= -1) out.write(c); in.close(); out.close(); Excep<on in thread "main" java.io.filenotfoundexcep<on: file1.txt (No such file or directory) at java.io.fileinputstream.open(na<ve Method) at java.io.fileinputstream.<init>(fileinputstream.java:137) at java.io.fileinputstream.<init>(fileinputstream.java:96) at es03.inputoutput1.copia(inputoutput1.java:24) at es03.inputoutput1.main(inputoutput1.java:45) 32
Java: I/O Esercizio: Cosa succede se il file dest non esiste? public void copia(string src, String dest) throws IOException { InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest); int c; while ((c = in.read())!= -1) out.write(c); in.close(); out.close(); Nessun Errore. Ancora una volta la soluzione migliore è aprire la Java doc e vedere il dehaglio dei metodi. 33
Java: I/O public class FileNotFoundExcep<on extends IOExcep<on Signals that an ahempt to open the file denoted by a specified pathname has failed. This excep<on will be thrown by the FileInputStream, FileOutputStream, and RandomAccessFile constructors when a file with the specified pathname does not exist. It will also be thrown by these constructors if the file does exist but for some reason is inaccessible, for example when an ahempt is made to open a read- only file for wri<ng. public class FileOutputStream extends OutputStream A file output stream is an output stream for wri<ng data to a File or to a FileDescriptor. Whether or not a file is available or may be created depends upon the underlying pla~orm. Some pla~orms, in par<cular, allow a file to be opened for wri<ng by only one FileOutputStream (or other file- wri<ng object) at a <me. In such situa<ons the constructors in this class will fail if the file involved is already open. 34
Java: I/O Esercizio: E qui cosa succede se src e dst non esistono? public void copia2(string src, String dest) throws IOException { Runtime.getRuntime().exec("cp " + src + " " + dest); Nessun Errore. La seman<ca di IOExcep<on cambia a seconda del contesto. In questo caso vogliamo poter mandare il nostro input alla shell. Il nostro contesto va completamente rivisto. Adesso la shell sarà il nostro file sul quale scrivere (eseguendo il comando). Il faho che src e dest non esistono è un problema dell applicazione shell, non più di Java. Quindi: Ragionare sempre su cosa s<amo facendo. Usare la Java documenta<on. 35