LuigiC++ ha scritto:
Il dubbio è, perchè sul primo codice mi viene dato l'errore "unreachble catch block" (credo perchè la println non causa errori)
Sì esatto. Un print o println non dichiara alcuna eccezione "checked". Quindi il compilatore
sa che quel try non potrà certo lanciare né MyExc1, né MyExc2, che sono entrambe checked (poiché estendono Exception). In Java avere del codice "
non raggiungibile" (per qualunque motivo sia, dovuto al flusso delle istruzioni) è un
errore di compilazione. In altri linguaggi come ad esempio Kotlin no, non lo è.
Nota che l'errore c'è solo per MyExc1/MyExc2. Queste due sono veramente "checked" poiché estendono Exception. Exception in sé è tecnicamente checked ma siccome è anche la base per RuntimeException (quelle unchecked), Exception è "dispensata" da questo controllo. Ovvero:
try {
System.out.print(4);
} catch (Exception e) {
System.out.print("exc");
}
è corretto e NON causa errore di compilazione. Perché quel catch
potrebbe catturare anche eccezioni unchecked, quindi è (e deve restare) lecito.
LuigiC++ ha scritto:
mentre sul secondo esercizio non mi viene dato? Nemmeno nel secondo esercizio può mai entrare nei catch "MyExc2" e "MyExc3", però non me lo segnala il compilatore.
Il secondo caso è diverso e per spiegarlo si può vedere quest'altro caso che è similare (usa solo checked per semplicità):
import java.io.*;
class IOExc1 extends IOException { }
class Prova {
public static void main(String[] args) {
try {
m();
} catch (IOExc1 e) {
System.out.println(1);
} catch (IOException e) {
System.out.println(2);
}
}
public static void m() throws IOExc1 {
}
}
In questo caso è tutto corretto, non ci sono errori di compilazione. Il m() è vuoto, materialmente non lancia nulla ma al compilatore non interessa (e non lo "sa"), guarda solo il throws. Siccome il throws dichiara IOExc1, il catch di IOExc1 è lecito, perché il m()
potrebbe lanciare IOExc1 (se lo modifichiamo).
Da Java 7 i compilatori Java sono "incoraggiati" dalle specifiche ad emettere un
warning per il catch di IOException, perché l'unica eccezione lanciata IOExc1 è quella già catturata. Ma il secondo catch resta comunque lecito.
Caso 2) Se invece il m() fosse:
public static void m() throws IOException {
}
Il codice è ancora tutto corretto senza errori. Il catch di IOExc1 non è "unreachable" perché il m()
potrebbe (teoricamente/tecnicamente) lanciare realmente IOExc1 e quindi il catch è lecito.
Caso 3) Se invece, per finire, il m() fosse:
public static void m() throws FileNotFoundException {
}
Allora qui il compilatore ha la prova schiacciante che il catch di IOExc1 è sbagliato perché il try non lo può causare. Quindi si ha un errore di compilazione sul catch di IOExc1.
Ecco, il tuo caso del
throw( new Exception() ) è concettualmente similare al Caso 2) che ho descritto.