Prévia do material em texto
EXCEÇÕES
Thaís Alves Burity Rocha
Agenda
Introdução
Tratamento de exceções
Declaração e lançamento de exceções
Hierarquia de exceções
Lançamento e tratamento de múltiplas exceções
Definição de classes de exceção
Introdução
No desenvolvimento de sistemas, uma preocupação
é a robustez
Sistemas robustos devem:
Fornecer formas eficientes para recuperação de falhas
Fornecer mensagens apropriadas de erros
Fazer validação dos dados
Garantir a consistência das operações
Retornar a um estado seguro e estável, permitindo que o
usuário execute outros comandos
Prevenir a perda de dados
Sistema Bancário
Como evitar débitos que deixam o saldo negativo?
O compilador apenas se preocupa com o uso correto da
linguagem
A “lógica” fica por conta do programador
Possíveis soluções:
Desconsiderar operação
Mostrar mensagem de erro
Retornar código de erro
public void debitar(double valor) {
saldo -= valor;
}
Prática antiga!
Sistema Bancário: Desconsiderar
Operação
Problemas
Não é possível identificar facilmente se a operação foi
realizada
Nenhuma informação é dada ao usuário do sistema
public void debitar(double valor) {
if (valor <= saldo) {
saldo -= valor;
}
}
Problemas
Nenhuma sinalização de erro é fornecida para o
código que invocou “debitar”, somente para o usuário
A mensagem é exibida no console
Sistema Bancário: Mostrar Mensagem
de Erro
public void debitar(double valor) {
if (valor <= saldo){
saldo -= valor;
}else {
System.out.println(“Saldo insuficiente!”);
}
}
Isso já foi feito
como exercício!
Sistema Bancário: Retornar Código de
Erro
Problemas
Dificulta a definição e o uso do método
A dificuldade é maior para métodos que retornam valores:
Se debitar já retornasse um outro valor qualquer, o que seria
feito?
public boolean debitar(double valor){
boolean r = false;
if (valor <= saldo) {
saldo = saldo - valor;
r = true;
}
return r;
}
Exceções
Significam uma condição excepcional, cuja
ocorrência altera o fluxo de execução normal do
programa
Surgem em tempo de execução
Podem ser geradas por diferentes causas
Desde falhas de hardware à bugs
Exemplo:
Acesso de memória indevido: Índice inválido para um
vetor
Exemplo de Exceção Não Tratada
public class DivisaoPorZero {
public static int dividir (int a, int b){
return a/b;
}
public static void main(String[] args){
System.out.println(“INICIO”);
DivisaoPorZero.dividir(9,0);
System.out.println(“FIM”);
}
}
1
2
3
4
5
6
7
8
9
10
Não chega a executar
SAÍDA:
INICIO
Exception in thread "main" java.lang.ArithmeticException: / by zero
at DivisaoPorZero.dividir(DivisaoPorZero.java:3)
at DivisaoPorZero.main(DivisaoPorZero.java:7)
Exceções em POO
São objetos que encapsulam informações relevantes
sobre o erro ocorrido
Quando um evento excepcional ocorre, é dito que
“uma exceção foi lançada”
Há uma clara separação entre o código que lança
a exceção e o código que trata a exceção
É possível usar um mesmo código para tratar uma
grande variedade de exceções (polimorfismo)
Tratamento de Exceções
Transfere a execução de um programa para
contornar a ocorrência de uma exceção, de
maneira apropriada
Logo, as exceções caracterizam situações
recuperáveis
Existem 2 formas
Capturar a exceção, usando blocos try/catch
“Desviar” a exceção
Tratamento de Exceções: try/catch
Exception é a superclasse de todas as exceções
Esse bloco catch captura qualquer exceção
try{
//executa algo arriscado
} catch(Exception ex){
//tenta resolver
}
Só executa se uma
exceção é lançada
Tratamento de Exceções: try/catch
public class DivisaoPorZero {
public static int dividir (int a, int b){
return a/b;
}
public static void main(String[] args){
System.out.println("INICIO");
try{
DivisaoPorZero.dividir(9,0);
} catch(Exception ex){
System.out.println("Não pode dividir por 0");
}
System.out.println("FIM");
}
}
Chamada do
código “arriscado”
SAÍDA:
INICIO
Não pode dividir por 0
FIM
Tratamento de Exceções:
try/catch/finally
Opcionalmente pode ser incluído um bloco finally
Ele sempre é executado, independente da exceção ser
lançada
try{
//executa algo arriscado
} catch(Exception ex){
//tenta resolver
} finally{
//executa algo de todo jeito
}
Tratamento de Exceções: finally
public class DivisaoPorZero {
public static int dividir (int a, int b){
return a/b;
}
public static void main(String[] args){
System.out.println("INICIO");
try{
DivisaoPorZero.dividir(9,0);
} catch(Exception ex){
System.out.println("Não pode dividir por 0");
} finally{
System.out.println("MEIO");
}
System.out.println("FIM");
}
}
SAÍDA:
INICIO
Não pode dividir por 0
MEIO
FIM
Tratamento de Exceções: finally
Adequado para escrita de código de “limpeza” ou
liberação de recursos
Exemplo: Fechamento de arquivo
Se nenhuma exceção for lançada, é executado logo
após o bloco try
Se alguma exceção for lançada, é executado logo
após o bloco catch que capturou a exceção
Tratamento de Exceções: finally
public static void exibirLinha(File arquivo){
Scanner scanner = null;
try {
scanner = new Scanner(arquivo);
if(scanner.hasNextLine()){
String linha = scanner.nextLine();
System.out.println(linha);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally{
if(scanner != null){
scanner.close();
}
}
}
Para instanciar um objeto File:
File arquivo = new File(“nome.txt”);
// se o arquivo não existia, ele é criado
Pode lançar
exceção
Fechamento
de recurso
Tratamento de Exceções: try-with-
resources
A partir de Java 7
Fechamento automático de recursos
public static void exibirLinha(File arquivo){
try (Scanner scanner = new Scanner(arquivo)){
if(scanner.hasNextLine()){
String linha = scanner.nextLine();
System.out.println(linha);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Se houver mais de um
recurso, separar por ;
Declaração e Lançamento de Exceção
Em regra geral, o código deve declarar que pode
lançar exceção
O lançamento é feito mediante a criação de um
objeto de exceção
public static int dividir (int a, int b) throws Exception{
if(b!=0){
return a/b;
}
else{
throw new Exception();
}
}
Sinaliza que o método
lança exceção
Lança exceção
O tipo da exceção lançada tem que
ser compatível com o tipo declarado
Hierarquia de Exceções
Exceções
não-verificadas
RuntimeException
Exceções
verificadasException
O compilador
verifica: Precisam ser
declaradas e tratadas
Exceções Verificadas
Precisam ser declaradas para serem lançadas
Precisam ser tratadas
Captura: try/cath
Repasse: Ainda será visto
A API define várias e o programador também
pode criar
int dividir (int a, int b){
if(b!=0) return a/b;
else throw new Exception();
}
Exceções Não-Verificadas
Não precisam ser declaradas nem tratadas
Caracterizam erros de lógica do código
Por exemplo: É possível se certificar que o índice não
ultrapassa o tamanho do vetor
Exemplos da API de Java
ArithmeticException (divisão por 0)
ArrayIndexOutOfBoundsException
ClassCastException
NullPointerException
Comportamento Polimórfico
Herança implica em polimorfismo
A divisão por 0 lança a exceção não-verificada
ArithmeticExceptiontry{
DivisaoPorZero.dividir(9,0);
}
catch(Exception ex){
}
try{
DivisaoPorZero.dividir(9,0);
}
catch(ArithmeticException ex){
}
Só captura
ArithmeticException
Captura qualquer
exceção, inclusive
ArithmeticException
Lançamento de Múltiplas Exceções
Um método pode lançar mais de uma exceção
A declaração do método deve incluir todas as
exceções verificadas que ele pode lançar
public void metodo() throws Tipo1, Tipo2, Tipo3{
...
}
Tratamento de Múltiplas Exceções
É possível ter um bloco catch para cada tipo de
exceção que pode ser lançada
Ou capturar todas as exceções com um único catch
Usando a superclasse
A boa prática consiste em dar tratamento
exclusivo quando necessário
try{...}
catch(Tipo1 ex){...}
catch(Tipo2 ex){...}
catch(Tipo3 ex){...}
A exceção só é
capturada por
um catch
Tratamento de Múltiplas Exceções
Quando uma exceção é lançada, a JVM procura
um bloco catch para o tipo da exceção
Blocos catch são analisados em sequência
Logo, blocos catch devem ser ordenados do tipo
mais específico para o tipo mais genérico
try {
obj.metodo();
} catch (Exception ex) {
System.out.println(ex);
} catch (IOException ex) {
System.out.println(ex);
}
}
Erro de compilação:
O segundo bloco
nunca será alcançado
Tratamento de Múltiplas Exceções:
multi-catch
Imagine um método que lança 3 tipos de exceção
2 tipos devem ter o mesmo tratamento
Ter 2 blocos catch que fazem a mesma coisa gera
duplicação de código
Usar catch(Exception ex) faz com que todos os
tipos de exceção recebam o mesmo tratamento
Uma alternativa é usar o multi-catch de Java 7
catch(IOException | SQLException ex) { ... }
Definição de Classes de Exceção
A API de Java provê várias classes de exceção, que
atendem às situações mais comuns
Quando o programador não encontra uma classe
adequada, ele pode definir sua própria classe de
exceção
Isso é possível através da criação de uma subclasse
de qualquer classe de exceção existente
O mais comum é criar uma subclasse de Exception
Definição de Classes de Exceção:
Exemplo de Declaração
public class SaldoInsuficenteException extends Exception{
public SaldoInsuficienteException(){
super(“Saldo insuficiente.”);
}
}
Boa prática: Sufixo Exception
Definição de Classes de Exceção:
Exemplo de Uso
public abstract class ContaAbstrata {
...
public abstract void debitar(double valor)
throws SaldoInsuficienteException;
}
public class Conta extends ContaAbstrata {
...
public void debitar(double valor)
throws SaldoInsuficienteException {
if (valor > saldo){
throw new SaldoInsuficienteException();
}
else{ saldo -= valor; }
}
}