Orientação a Objetos e a Linguagem Java Afrânio Assis [email protected] Novembro/2006 1 Exceções e Tratamento de Erros Novembro/2006 2 Introdução • Nem todos os erros podem ser detectados em tempo de compilação (Ex: Divisão por zero). • Algumas linguagens, como C, tratam esses erros através do retorno de valores especiais (-1, 0, 1) e da modificação de flags globais. • Nesses casos, quem recebe o erro deve verificar o valor retornado ou a flag global para descobri-lo. Novembro/2006 3 Introdução • Em Java, os erros que não podem ser detectados em tempo de compilação são chamados Exceções. • Algumas situações indesejáveis também podem ser definidas como exceções. • Java oferece um mecanismo para o tratamento de exceções, que torna o código mais legível. Novembro/2006 4 Lançamento de Exceções • No ponto da ocorrência de uma exceção: – geralmente, não sabemos o que fazer – sabemos que não podemos continuar, devemos parar – alguém, em algum lugar, deve saber o que fazer, ou seja, deve saber tratar a exceção. • Quando uma exceção ocorre, o fluxo normal de execução é interrompido e um objeto que representa a exceção é criado e lançado. y = 0; x = x / y; Novembro/2006 // Divisão por zero! Exceção lançada 5 Lançamento de Exceções • Em um local apropriado a exceção será capturada e tratada. • No tratamento deve ser feito o que for necessário para que o programa continue funcionando normalmente e para que os interessados saibam o que ocorreu. • Uma exceção também pode ser lançada pelo próprio programador. if (y == 0) throw new ArithmeticException(); x = x / y; Novembro/2006 6 Lançamento de Exceções if (y == 0) throw new ArithmeticException(“divisão por zero!”); x = x / y; throw <objeto_exceção>; • A palavra reservada throw – O fluxo de execução normal é interrompido – A execução continua no local de tratamento da exceção – Podemos lançar qualquer objeto do tipo Throwable (que possui as subclasses Erro e Exception) Novembro/2006 7 Capturando uma Exceção • Vantagem do tratamento de exceções em Java – O programador se preocupa apenas com a essência do problema, casos excepcionais são tratados em outro lugar • Conceito de região protegida – Trecho de código que pode produzir exceções, seguido do código que pode tratar tais exceções • O bloco try – Bloco que delimita o trecho de código protegido com relação ao surgimento de exceções try { // região protegida } Novembro/2006 8 Capturando uma Exceção • Manipuladores de exceção – – – – – a exceção lançada deve ser tratada em algum lugar este lugar é o manipulador de exceção existe um para cada tipo de exceção seguem imediatamente o bloco try denotados pela palavra reservada catch try { // região protegida } catch (Tipo1 id1) {} catch (Tipo2 id2) {} Novembro/2006 9 Capturando uma Exceção try { if (y == 0) throw new ArithmeticException("divisão por zero!"); x = x / y; } catch(ArithmeticException e){ //tratamento da exceção } • Cada cláusula catch (manipulador de exceção) – É como se fosse um método com um único parâmetro – Identificador pode ser utilizado normalmente dentro do escopo Novembro/2006 10 Capturando uma Exceção • Mecanismo de tratamento de exceções – procura a primeira cláusula catch que case com o tipo de exceção que foi lançada – ao entrar no manipulador de exceção, a exceção é considerada tratada – busca por novos manipuladores termina • busca apenas um manipulador Novembro/2006 11 Criando Classes de Exceções • Podemos criar nossas próprias classes de exceções – Útil se forem gerados erros não previstos na hierarquia de classes de exceções de Java – Temos que herdar de alguma classe de exceção da hierarquia de exceções de Java • Devemos procurar uma exceção que possua sentido próximo (coerente) da exceção que estamos criando Novembro/2006 12 // Inheriting your own exceptions. class SimpleException extends Exception {} public class SimpleExceptionDemo { public void m() throws SimpleException { System.out.println("Throwing SimpleException from m()"); throw new SimpleException (); } public static void main(String[] args) { SimpleExceptionDemo sed = new SimpleExceptionDemo(); try { sed.m(); } catch(SimpleException e) { System.err.println("Caught it!"); } } } Throwing SimpleException from m() Caught it! Novembro/2006 13 Criando Classes de Exceções • Comentários – O nome da classe deve fazer sentido! Ex: IOException, PrintException, CloneNotSupportedException, ... – Temos que informar quando um método levanta uma exceção não tratada internamente (throws) – Saída de erro padrão (System.err) Novembro/2006 14 // Inheriting your own exceptions. class MyException extends Exception { public MyException() {} // constructor with parameter // call to the superclass constructor public MyException(String msg){ super(msg); } } public class FullConstructors { public static void f() throws MyException { System.out.println("Throwing MyException from f()"); throw new MyException(); } public static void g() throws MyException { System.out.println("Throwing MyException from g()"); throw new MyException("Originated in g()"); } Novembro/2006 15 public static void main(String[] args) { try { FullConstructors.f(); } catch(MyException e) { e.printStackTrace(System.err); } try { FullConstructors.g(); } catch(MyException e) { e.printStackTrace(System.err); } } } Novembro/2006 16 Pilha de execução impressa na saída padrão de erro Throwing MyException from f() MyException at FullConstructors.f(FullConstructors.java:16) at FullConstructors.main(FullConstructors.java:28) Throwing MyException from g() MyException: Originated in g() at FullConstructors.g(FullConstructors.java:22) at FullConstructors.main(FullConstructors.java:37) Mensagem passada no momento que a exceção foi criada Novembro/2006 17 Palavra reservada throws • Informa ao programador cliente que um método pode lançar uma exceção • Compõe a assinatura do método • Não confundir com a palavra reserveda throw void f() throws TooBigException, TooSmallException { //... } Novembro/2006 18 Palavra reservada throws • O uso de throws é obrigatório quando um método lança uma exceção. • O throws também pode ser usado sem que a exceção declarada seja realmente lançada pelo método. – útil na criação de superclasses e interfaces Novembro/2006 19 A classe Exception • A classe mãe de todas as exceções em Java • O trecho abaixo trata qualquer exceção catch (Exception e) { // Tratamento de qualquer exceção filha da // classe “Exception” } Novembro/2006 20 A classe Exception • Métodos – String getMessage() - retorna a mensagem informada na criação da exceção – String getLocalizedMessage() - se não for sobrescrito na subclasse, retorna a mesma mensagem do método anterior. A idéia é que ele seja sobrescrito e explique melhor a exceção. – String toString() – informa o nome da classe e a mensagem passada na criação da exceção. – void printStackTrace() – imprime a pilha de execução na saída padrão. Novembro/2006 21 Relançado uma Exceção • Relançando uma exceção try { //.... } catch (Exception e) { //Aqui a exceção é tratada. Em seguida, ela é //relançada, conforme pode ser visto a seguir: throw e; } • Um novo manipulador de exceção será procurado em um contexto de mais alto nível Novembro/2006 22 Relançado uma Exceção try { //.... } catch (IOException e) { throw e; } catch (Exception e) { //.... } • Quando existir mais de catch para um mesmo try, a exceção relançada não será tratada nos blocos catch seguintes Novembro/2006 23 Relançado uma Exceção • Quando relançado, o objeto exceção é preservado, ou seja, ele mantém a informação da pilha de execução original. • Quando capturamos uma exceção podemos lançar uma outra exceção, diferente da capturada. – útil quando queremos esconder algumas exceções dos clientes de bibliotecas Novembro/2006 24 Hierarquia de Exceções Throwable Exception Error RunTimeException Novembro/2006 25 Hierarquia de Exceções • Classe Throwable – tudo que pode ser “lançado” como erro – subclasses Error e Exception – classe Error • erros críticos • geralmente não nos preocupamos com eles • há pouco a ser feito quando ocorre, por exemplo, um erro por falta de memória (OutOfMemoryError) ou porque uma classe não foi encontrada (NoClassDefFoundError) – classe Exception • tipo base de todas as exceções dos programas Novembro/2006 26 Hierarquia de Exceções • Caso especial: RunTimeException (herda de Exception) – classes de exceções levantadas automaticamente pelo ambiente Java – não precisamos incluí-las na cáusula throws de um método – ArithmeticException é um tipo de RunTimeException y = 0; x = x / y; Novembro/2006 // Divisão por zero! 27 Hierarquia de Exceções • O que acontece quando não capturamos uma RunTimeException? – a exceção é repassada pelos métodos até o main() – ao sair do programa, printStackTrace() é chamado para a exceção • RunTimeException representa erros que, geralmente, são inconvenientes de verificar – receber uma referência null como parâmetro de método – acesso fora dos limites de um array Novembro/2006 28 A palavra reservada finally • Usada para definir um bloco de comandos que serão executados independentemente de uma exceção ocorrer ou não • Localizada após os manipuladores de exceção (blocos catch) try { /* região protegida */ } catch (TipoExcecao1 e1) {} catch (TipoExcecao2 e2) {} finally { // comando finais sempre executados } Novembro/2006 29 // The finally clause is always executed. class ThreeException extends Exception {} public class FinallyWorks { static int count = 0; public static void main(String[] args) { while(true) { try { if(count++ == 0) // Post-increment is zero first time throw new ThreeException(); System.out.println("No exception"); } catch(ThreeException e) { System.err.println("ThreeException"); } finally { System.err.println("In finally clause"); if(count == 2) break; // out of "while" } } ThreeException } In finally clause } No exception In finally clause Novembro/2006 30 A palavra reservada finally • Útil para – fechar de arquivos – fechar de conexões de rede – desfazer alguma transação feita pela metade – ... Novembro/2006 31 // Motivação para o uso do finally class Switch { boolean state = false; boolean read() { return state; } void on() { state = true; } void off() { state = false; } } class OnOffException1 extends Exception {} class OnOffException2 extends Exception {} Novembro/2006 32 public class OnOffSwitch { static Switch sw = new Switch(); static void f() throws OnOffException1, OnOffException2 {} public static void main(String[] args) { try { sw.on(); f(); // Code that can throw exceptions... sw.off(); // Poderia estar no finally } catch(OnOffException1 e) { System.err.println("OnOffException1"); sw.off(); // Poderia estar no finally } catch(OnOffException2 e) { System.err.println("OnOffException2"); sw.off(); // Poderia estar no finally } } } Novembro/2006 33 // Usando o finally teriamos: public class OnOffSwitch { static Switch sw = new Switch(); static void f() throws OnOffException1, OnOffException2 {} public static void main(String[] args) { try { sw.on(); // Code that can throw exceptions... f(); } catch(OnOffException1 e) { System.err.println("OnOffException1"); } catch(OnOffException2 e) { System.err.println("OnOffException2"); } finally { sw.off(); } } } Novembro/2006 34 Reagindo a exceções • Quando ocorrer uma exceção podemos: – chamar novamente o método que a provocou passando novos parâmetros ou continuar sem chamar tal método – calcular um resultado alternativo – fazer o que for possível no contexto corrente e relançar a mesma exceção para um contexto mais alto ou lançar outra exceção – finalizar o programa Novembro/2006 35 Considerações Finais • A escrever o seguinte código: • Ele captura até NullPointerException, mas não faz nenhum tratamento. • Ninguém saberá que um erro ocorreu. Novembro/2006 36 Resumo do Funcionamento 1)Uma exceção é gerada; 2)A execução é interrompida; 3)Um objeto exceção é criado; 4)Uma referência a ele é direcionada para fora do contexto atual; 5)O mecanismo de tratamento de exceções começa a procurar pelo manipulador de exceção apropriado para continuar a execução do programa; 6)Nele o problema é tratado, com objetivo de que o programa possa continuar executando. Novembro/2006 37