Il linguaggio di programmazione Java usa le eccezioni per gestire gli errori e altri eventi eccezionali.
Un'eccezione è un evento che si verifica durante l'esecuzione di un programma e che interrompe il normale flusso delle istruzioni. In Java le eccezioni vengono sollevate esplicitamente, e l'atto di sollevare un'eccezione si chiama lanciare un'eccezione. L'atto di gestire un'eccezione si chiama catturare un'eccezione.
In Java, tutte le eccezioni sono sottoclassi della classe Exception, che a sua volta è una sottoclasse di Throwable.
Java distingue due tipi di eccezioni:
Le eccezioni controllate sono condizioni eccezionali che un'applicazione dovrebbe prevedere e dalle quali dovrebbe riprendersi.
Un esempio di eccezione controllata è FileNotFoundException, che si verifica quando un metodo cerca di leggere un file che non esiste.
Questo tipo di eccezione viene controllato in fase di compilazione: i metodi che lanciano eccezioni controllate devono specificarlo nella loro firma, ed il codice che chiama un metodo che potrebbe lanciare un'eccezione controllata deve gestirla, altrimenti non verrà compilato.
Tutte le eccezioni controllate sono sottoclassi di Exception che non estendono RuntimeException.
Le eccezioni non controllate sono condizioni eccezionali che un'applicazione di solito non può prevedere e dalle quali non può riprendersi.
Un esempio di eccezione non controllata è NullPointerException, che si verifica quando un metodo che si aspetta un valore non nullo riceve invece null.
Questo tipo di eccezione non viene controllato in fase di compilazione: i metodi che lanciano eccezioni non controllate non devono specificarlo nella loro firma, ed il codice che chiama un metodo che potrebbe lanciare un'eccezione non controllata non è tenuto a gestirla.
Tutte le eccezioni non controllate ereditano da RuntimeException, che a sua volta estende Exception.
Un metodo in Java può lanciare un'eccezione usando l'istruzione throw.
Quando si lancia un'eccezione controllata da un metodo, è necessario specificarlo nella firma del metodo usando la parola chiave throws, come mostra l'esempio seguente.
Questo obbliga il codice chiamante a prevedere che possa essere lanciata un'eccezione e a gestirla di conseguenza.
public class InsufficientBalanceException extends Exception {
}
public class BankAccount {
public void withdraw(double amount) throws InsufficientBalanceException {
if (balance < amount) {
throw new InsufficientBalanceException();
}
// rest of the method implementation
}
}
Quando si lancia un'eccezione non controllata da un metodo, non è necessario specificarlo nella firma del metodo, anche se è supportato.
public class BankAccount {
public void withdraw(double amount) {
if (amount < 0) {
throw new IllegalArgumentException("Cannot withdraw a negative amount");
}
// rest of the method implementation
}
}
In Java la gestione delle eccezioni avviene con le parole chiave try, catch e finally.
try.try è seguito da uno o più blocchi catch che catturano le eccezioni lanciate nel blocco try.catch sono facoltativamente seguiti da un blocco finally che viene sempre eseguito dopo il blocco try, indipendentemente dal fatto che sia stata lanciata o meno un'eccezione.L'esempio seguente mostra come funzionano queste parole chiave:
public class ATM {
public void withdraw(BankAccount bankAccount, double amount) {
try {
System.out.println("Withdrawing " + amount);
bankAccount.withdraw(amount);
System.out.println("Withdrawal succeeded");
} catch (InsufficientBalanceException) {
System.out.println("Withdrawal failed: insufficient balance");
} catch (RuntimeException e) {
System.out.println("Withdrawal failed: " + e.getMessage());
} finally {
System.out.println("Current balance: " + bankAccount.getBalance());
}
}
}
In questo esempio, quando non viene lanciata alcuna eccezione, viene stampato quanto segue:
Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0
Se invece l'istruzione bankAccount.withdraw(amount) lancia un'InsufficientBalanceException, viene stampato quanto segue:
Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0
Oppure, se bankAccount.withdraw(amount) lancia un'eccezione non controllata, viene stampato quanto segue:
Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
Java ha anche una categoria separata chiamata Errori, che sono problemi gravi esterni all'applicazione.
Un esempio di errore è OutOfMemoryError, che si verifica quando un'applicazione cerca di usare più memoria di quanta ne sia disponibile nel sistema.
Come le eccezioni non controllate, gli errori non vengono controllati in fase di compilazione. La differenza è che rappresentano problemi a livello di sistema e sono generalmente lanciati dalla Java Virtual Machine o dall'ambiente invece che dall'applicazione. Generalmente le applicazioni non dovrebbero tentare di catturarli o gestirli.
Tutti gli errori in Java ereditano dalla classe Error.
In questo esercizio costruirai la gestione degli errori per una semplice calcolatrice di numeri interi. Per semplificare le cose, i metodi per calcolare addizione, moltiplicazione e divisione sono già forniti.
L'obiettivo è avere una calcolatrice funzionante che restituisce una stringa con il seguente formato: 16 + 51 = 67, quando riceve come argomenti 16, 51 e +.
CalculatorConundrum calculator = new CalculatorConundrum();
calculator.calculate(16, 51, "+");
// => returns "16 + 51 = 67"
calculator.calculate(32, 6, "*");
// => returns "32 * 6 = 192"
calculator.calculate(512, 4, "/");
// => returns "512 / 4 = 128"
Il metodo principale da implementare in questa attività sarà il metodo CalculatorConundrum.calculate().
Richiede tre argomenti.
I primi due argomenti, operand1 e operand2, sono numeri interi su cui verrà eseguita un'operazione.
Il terzo argomento, operation, è di tipo String e per questo esercizio è necessario implementare le seguenti operazioni:
+
*
/
Aggiorna il metodo CalculatorConundrum.calculate() per gestire le operazioni non valide:
operation è null, va lanciata un'IllegalArgumentException con il messaggio Operation cannot be null.operation è "", va lanciata un'IllegalArgumentException con il messaggio Operation cannot be empty.operation è un'operazione diversa da +, * o /, va lanciata un'IllegalOperationException con il messaggio Operation '{operation}' does not exist.calculator.calculate(10, 1, null);
// => throws IllegalArgumentException with message "Operation cannot be null"
calculator.calculate(10, 1, "");
// => throws IllegalArgumentException with message "Operation cannot be empty"
calculator.calculate(10, 1, "-");
// => throws IllegalOperationException with message "Operation '-' does not exist"
In Java, tentare di dividere per zero lancia un'ArithmeticException.
Aggiorna il metodo CalculatorConundrum.calculate() per intercettare questa eccezione e lanciare poi un'IllegalOperationException con il messaggio Division by zero is not allowed e l'ArithmeticException intercettata come causa.
calculator.calculate(512, 0, "/");
// => throws IllegalOperationException with message "Division by zero is not allowed"
Iscriviti a Exercism per imparare e padroneggiare Java con 26 concetti158 esercizi e il mentoring di persone reali, tutto gratis.