A linguagem de programação Java usa exceções para tratar erros e outros eventos excecionais.
Uma exceção é um evento que ocorre durante a execução de um programa e que perturba o fluxo normal das instruções. Em Java, as exceções são lançadas explicitamente, e o ato de lançar uma exceção chama-se lançar uma exceção. O ato de tratar uma exceção chama-se capturar uma exceção.
Em Java, todas as exceções são subclasses da classe Exception, que por sua vez é uma subclasse de Throwable.
Java distingue dois tipos de exceções:
As exceções verificadas são condições excecionais que uma aplicação deve prever e das quais deve recuperar.
Um exemplo de exceção verificada é a FileNotFoundException, que ocorre quando um método tenta ler um ficheiro que não existe.
Este tipo de exceção é verificado em tempo de compilação: os métodos que lançam exceções verificadas devem indicá-lo na sua assinatura, e o código que chama um método que possa lançar uma exceção verificada tem de a tratar, caso contrário não compila.
Todas as exceções verificadas são subclasses de Exception que não estendem RuntimeException.
As exceções não verificadas são condições excecionais que uma aplicação normalmente não consegue prever ou das quais não consegue recuperar.
Um exemplo de exceção não verificada é a NullPointerException, que ocorre quando um método que espera um valor não nulo recebe null.
Este tipo de exceção não é verificado em tempo de compilação: os métodos que lançam exceções não verificadas não são obrigados a indicá-lo na sua assinatura, e o código que chama um método que possa lançar uma exceção não verificada não é obrigado a tratá-la.
Todas as exceções não verificadas herdam de RuntimeException, que por sua vez é uma extensão de Exception.
Um método em Java pode lançar uma exceção com a instrução throw.
Ao lançar uma exceção verificada a partir de um método, é obrigatório indicá-lo na assinatura do método com a palavra-chave throws, como mostra o exemplo abaixo.
Isto obriga o código que faz a chamada a prever que uma exceção possa ser lançada e a tratá-la em conformidade.
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
}
}
Ao lançar uma exceção não verificada a partir de um método, não é obrigatório indicá-lo na assinatura do método, embora isso seja permitido.
public class BankAccount {
public void withdraw(double amount) {
if (amount < 0) {
throw new IllegalArgumentException("Cannot withdraw a negative amount");
}
// rest of the method implementation
}
}
Em Java, o tratamento de exceções faz-se com as palavras-chave try, catch e finally.
try.try é seguido por um ou mais blocos catch, que capturam as exceções lançadas no bloco try.catch são opcionalmente seguidos por um bloco finally, que é sempre executado depois do bloco try, independentemente de ter sido lançada ou não uma exceção.O exemplo seguinte mostra como estas palavras-chave funcionam:
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());
}
}
}
Neste exemplo, quando não é lançada nenhuma exceção, é impresso o seguinte:
Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0
No entanto, caso a instrução bankAccount.withdraw(amount) lance uma InsufficientBalanceException, é impresso o seguinte:
Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0
Ou, caso seja lançada uma exceção não verificada por bankAccount.withdraw(amount), é impresso o seguinte:
Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
Java tem também uma categoria separada chamada Errors, que são problemas graves externos a uma aplicação.
Um exemplo de erro é o OutOfMemoryError, que ocorre quando uma aplicação tenta usar mais memória do que a disponível no sistema.
Tal como as exceções não verificadas, os erros não são verificados em tempo de compilação. A diferença é que representam problemas ao nível do sistema e são geralmente lançados pela máquina virtual Java ou pelo ambiente, e não pela aplicação. As aplicações não devem, em geral, tentar capturá-los ou tratá-los.
Em Java, todos os erros herdam da classe Error.
Como foi dito antes, as exceções são eventos que perturbam o fluxo normal das instruções e servem para tratar eventos excecionais. Por isso, não é recomendado usar exceções para controlar o fluxo da tua aplicação.