Baixe o app para aproveitar ainda mais
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; } } }
Compartilhar