Chiarimento comportamento clausole catch - eccezioni

di il
1 risposte

Chiarimento comportamento clausole catch - eccezioni

Salve a tutti, sono alle prese con alcuni esercizi in Java più in particolare sulle eccezioni e mi trovo bloccato su un punto:
Posto due codici:
Codice 1:
class MyExc1 extends Exception { }
class MyExc2 extends Exception { }
class MyExc3 extends MyExc2 { }
public class A1 {
public static void main(String [] argv)
throws Exception {
try {
m();
System.out.print(1);
}
catch( Exception u ) {
System.out.print(2);
}
finally {
System.out.print(3);
throw( new MyExc2() );
}
}
static void m()
throws Exception {
try {
System.out.print(4);
}
catch( MyExc2 t ) { //unrechable catch block!!
System.out.print(5);
}
catch( MyExc1 h ) {
throw( new MyExc1() );
}
catch( Exception b ) {
}
finally {
System.out.print(6);
}
}
}
Codice 2:
class MyExc1 extends Exception { }
class MyExc2 extends Exception { }
class MyExc3 extends Exception { }
public class D1 {
public static void main(String [] argv)
throws Exception {
try {
n();
}
catch( MyExc1 a ) {
}
catch( MyExc3 j ) {
throw( new MyExc2() );
}
finally {
System.out.print(1);
throw( new Exception() );
}
}
static void n()
throws Exception {
try {
throw( new Exception() );
}
catch( MyExc2 t ) {
}
catch( MyExc3 h ) {
System.out.print(2);
}
catch( Exception z ) {
System.out.print(3);
throw( new MyExc2() );
}
finally {
System.out.print(4);
throw( new MyExc1() );
}
}
}
L'esercizio richiede di stabilire gli output degli esercizi e/o eventualmente gli errori di compilazione che mostra. Il dubbio è, perchè sul primo codice mi viene dato l'errore "unreachble catch block" (credo perchè la println non causa errori), 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. Quindi mi chiedo, con quale criterio Java stabilisce se un catch è raggiungibile oppure no? Dipende dalla gerarchia e dal "collegamento" delle classi delle eccezioni?

1 Risposte

  • Re: Chiarimento comportamento clausole catch - eccezioni

    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.
Devi accedere o registrarti per scrivere nel forum
1 risposte