Le eccezioni in Java

Quando si verifica una situazione anomala in un programma Java (se questa non è gestita), la JVM interrompe l'esecuzione del programma stesso e crea una eccezione.

L'eccezione altro non è che un oggetto che permette di ottenere informazioni quali:

  • il tipo di anomalia che si è verificata.
    Questa informazione è ricavabile dal tipo (classe) dell'oggetto eccezione generato.
    Ogni eccezione è infatti un oggetto del tipo di una classe che deriva, direttamente o indirettamente, dalla classe Throwable
  • un messaggio descrittivo dell'anomalia avvenuta. Per recuperare tale messaggio, le eccezioni dispongono di un apposito metodo, chiamato getMessage
  • lo stack trace, ossia una rappresentazione testuale del call stack, cioè della sequenza di funzioni chiamate ed in esecuzione a partire dal main, fino alla funzione in cui è avvenuta l'anomalia

Facciamo un esempio per capire meglio i concetti.

Supponiamo di avere il seguente programma in Java che chiede all'utente di inserire due numeri interi e calcola il quoziente della divisione.

import java.util.Scanner;

public class CalcoloQuoziente {
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        System.out.print("Inserisci il dividendo: ");
        int dividendo = sc.nextInt();
        
        System.out.print("Inserisci il divisore: ");
        int divisore = sc.nextInt();
        
        int quoziente = quoziente(dividendo, divisore);
        
        System.out.println("Il quoziente della divisione tra " + dividendo + 
            " e " + divisore + " è " + quoziente);
    }
    
    public static int quoziente(int dividendo, int divisore) {
        return dividendo / divisore;
    }
}

Se l'utente inserisce come dividendo il valore 10 e come divisore il valore 3, l'esecuzione del programma apparirà come evidenziato di seguito.

Inserisci il dividendo: 10
Inserisci il divisore: 3
Il quoziente della divisione tra 10 e 3 è 3

Se invece l'utente inserisse come dividendo 10 e come divisore 0, l'output dell'esecuzione del programma sarebbe il seguente.

Inserisci il dividendo: 10
Inserisci il divisore: 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
   at CalcoloQuoziente.quoziente(CalcoloQuoziente.java:21)
   at CalcoloQuoziente.main(CalcoloQuoziente.java:14)

Analizziamo nel dettaglio che cosa è avvenuto.

La JVM ha provato ad eseguire la funzione che calcola la divisione tra i due valori inseriti ma, per ovvie e note ragioni, non è stata in grado di calcolare la divisione tra 10 e 0.
Di conseguenza, ha generato una eccezione e ne ha stampato le informazioni precedentemente elencate.
Analizziamole una ad una.
Nella prima riga troviamo il tipo di anomalia che si è verificata.
ArithmeticException sta ad indicare che è avvenuta una anomalia eseguendo un calcolo aritmetico.
Sempre nella prima riga troviamo la descrizione, / by zero, che sta ad indicare che è stato chiesto di calcolare una divisione (/) per zero.

Le due righe successive costituiscono lo stack trace, ossia la descrizione della sequenza di chiamate di funzioni avvenute partendo dal main, fino al momento in cui si è presentata l'anomalia.

Infatti, l'esecuzione del nostro programma è iniziata dal metodo main che, alla riga 14, ha invocato la funzione quoziente che, a sua volta, alla riga 21, ha eseguito l'istruzione di divisione che è fallita in quanto il divisore era nullo.

Le chiamate delle funzioni avvenute sono indicate a partire dalla funzione in cui è avvenuta l'anomalia e procedendo a ritroso in tutte le funzioni coinvolte, fino a giungere alla funzione main, dalla quale è iniziata l'esecuzione del programma.
Questa caratteristica, di indicare le informazioni dalla più recente alla meno recente, è tipica delle strutture stack o pila, che analizzeremo più nel dettaglio quando tratteremo le strutture dati complesse.