Gestione errori in Java

In C si fanno una serie di controlli prima di chiamare una funzione che potrebbe far crashare il programma. In Java si preferisce utilizzare una tecnica più moderna, prima si esegue il codice, se puoi questo genera un errore lo si gestisce senza far crashare il programma. Come si fa? Vediamo subito!

Try e Catch

Il codice a rischio di errore viene scritto in un blocco try {}, al di sotto di esso si inserisce il blocco catch{} dove si gestiscono gli eventuali errori ricevuti. Vediamo un esempio:

import java.util.Date;

public class Main {

    public static void main(String[] args) { 

        Date j = new Date();

        //Assegno null a j, in modo da far generare un'eccezione
        j = null;

        try{

            //Questa riga fa generare una NullPointerException
            j.getTime();
        }
        catch(Exception e){

            //Catturo l'eccezione e la stampo
            System.out.println("Errore: " + e);
        }

        //Ciao viene eseguito comunque, il programma non crasha
        System.out.println("CIAO");

    }
}

Qui assegno null a j, ma il programma non crasha perchè l'eccezzione viene gestita.

Exception rappresenta un'eccezione generale, è sempre buona cosa specificare il tipo di eccezione per evitare comportamenti che non ci aspettiamo dal codice. Sempre per lo stesso motivo è buona cosa usare diversi catch per ogni tipo di eccezione.

import java.util.Date;

public class Main {

    public static void main(String[] args) { 

        Date j = new Date();

        //Assegno null a j, in modo da far generare un'eccezione
        j = null;

        try{

            //Questa riga fa generare una NullPointerException
            j.getTime();
        }
        catch(NullPointerException e){

            //Catturo la NUllPointerExecption e la stampo
            System.out.println("Errore: " + e);
        }
        catch(Exception e){

            //Catturo l'eccezione e la stampo
            System.out.println("Questo non dovrebbe succedere");
        }

        //Ciao viene eseguito comunque, il programma non crasha
        System.out.println("CIAO");

    }
}
Errore: java.lang.NullPointerException: Cannot invoke "java.util.Date.getTime()" because "j" is null
CIAO

Finally

L'Aggiunta del blocco finally {} ci permette di eseguire delle operazioni dopo il try anche se si genera un'eccezione. Questo può ci risultarci molto utile quando dobbiamo avviare un server e dobbiamo poi chiuderlo. Vediamo un breve esempio.

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class Main {

    public static void main(String[] args) { 

        try{

            //Creo un server
            ServerSocket server = new ServerSocket(5000);

            try{

                //Aspetto un client
                Socket socket = server.accept();
                DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
                
                //Gli mando 'Ciao'
                stream.writeUTF("Ciao");
                
                //chiudo la connessione
                stream.close();
                socket.close();
            }

            catch(SocketTimeoutException e){

                System.out.println("Errore di Timeout");
            }

            catch(IOException e){

                System.out.println("Errore di IO");
            }   

            finally{

                //chiudo il server
                server.close();
            }
        }

        catch(IOException e){

            System.out.println("Il server si è chiuso per errore :( ");
        }  

        catch(Exception e){

            System.out.println("Qualcosa è andato storto :( ");
        }
    }
}
© Nicola Bovolato 2020