Seminrio Manipulao de excees em Java Fabiana Piesigilli
Seminário: Manipulação de exceções em Java Fabiana Piesigilli Rodrigo Mendes Leme MAC 441 - Programação Orientada a Objetos
Introdução
Introdução w Mundo ideal: dados estão sempre na forma certa, arquivos desejados sempre existem, etc. w Mundo real: dados ruins e bugs podem arruinar o programa.
Introdução w Necessidade de mecanismos para tratamento de erros. w Antes da POO: n n Variável global inteira com valores de 0 até n. Na ocorrência de uma exceção: Variável assumia um valor. l Remetia uma mensagem de erro. l Encerrava o programa. l
Introdução w Depois da POO: n n Classes de erros. Possíveis tipos de erros e seus tratamentos são agrupados. Não há necessidade de interromper o programa. O mesmo erro é tratado quantas vezes for necessário.
Introdução w Idéia básica: “código ruim não será executado”. w Nem todos os erros podem ser detalhados em tempo de compilação. w Os que não podem devem ser lidados em tempo de execução. w Estes últimos são o alvo da manipulação de exceções.
Introdução w Premissa básica: separar o processamento normal da manipulação de erros. w Vantagens desse mecanismo: n n n Permite concentrar em lugares diferentes o “código normal” do tratamento do erro. Simplifica a criação de programas grandes usando menos código. Torna o código mais robusto, ao garantir que não há erros sem tratamento.
Exceções - básico
Hierarquia de exceções de Java Throwable Error Exception . . . IOException Run. Time. Exception . . .
w Exceção: problema que impede a continuação do método ou escopo em execução. w Importante: exceção ¹ problema normal. w Problema normal: há informação suficiente no contexto atual para lidar com ele. w Exceção: não há informação suficiente. w Disparar uma exceção: sair do contexto atual e relegar a solução a um contexto mais abrangente.
Exceções: Básico w Ao disparar-se uma exceção, ocorre a seguinte sequência de eventos: n n Um objeto exceção é criado. A execução é interrompida. O mecanismo de manipulação de exceções assume o controle o procura o manipulador de exceção adequado. O manipulador da exceção trata o problema.
w Exemplo: seja t uma referência para um objeto, que pode não ter sido inicializado. if (t == null) throw new Null. Pointer. Exception(); w A palavra chave throw dispara uma exceção e dá início à sequência de eventos citada anteriormente.
w Outra versão: if (t == null) throw new Null. Pointer. Exception (“t = null”); w Este construtor permite colocar informações pertinentes na exceção, que posteriormente podem ser extraídas usando outros métodos.
w Em resumo, disparar uma exceção é fácil: n n n 1) Escolha uma classe de exceção apropriada. 2) Instancie um objeto dessa classe. 3) Dispare-o. throw new EOFException(); (3) (2) (1)
Capturando exceções
Capturando exceções w Quando uma exceção é disparada, em algum lugar ela deve ser capturada. w Região protegida: trecho de código que pode gerar exceções. w Manipuladores de exceções: tratam as exceções que ocorreram dentro da região protegida. Vêm imediatamente após a mesma.
w Em Java: n n try: indica a região protegida. catch: manipula uma exceção. Formato básico: try { // Código } catch(Classe. De. Exceção e) { // Manipula aquele tipo de erro }
w Pode-se usar vários manipuladores: try {. . . } catch(Classe. De. Excecao 1 c 1) {. . . } catch(Classe. De. Excecao 2 c 2) {. . . } catch(Classe. De. Excecao 3 c 3) {. . . }. . .
Capturando exceções w Processo: w A exceção é disparada dentro de um bloco try. w O mecanismo de manipulação de exceção procura o primeiro catch cujo tipo de exceção bata com a exceção disparada. w O mecanismo entra no bloco do catch e o erro é tratado.
w Exemplo: método para ler caracteres de um arquivo. public static String read. String() { int carac; String cad = “”; boolean terminou = false; while (!terminou) {
try { carac = System. in. read(); if (carac < 0 || (char) carac == `n`) terminou = true; else cad = cad + (char) carac; } catch(IOException e) { terminou = true; }. . .
CRIANDO SUAS PRÓPRIAS EXCEÇÕES
class My. Exception extends Exception { public My. Exception() {} public My. Exception(String msg) { super(msg); } } public class Inheriting { public static void f() throws My. Exception { System. out. println("Throwing My. Exception from f()"); throw new My. Exception(); } public static void g() throws My. Exception { System. out. println("Throwing My. Exception from g()"); throw new My. Exception("Originated in g()"); } public static void main(String[] args) { try { f(); } catch(My. Exception e) { e. print. Stack. Trace(); } try { g(); } catch(My. Exception e) { e. print. Stack. Trace(); } } }
Criando suas próprias exceções Throwing My. Exception from f() My. Exception at Inheriting. f(Inheriting. java: 16) at Inheriting. main(Inheriting. java: 24) Throwing My. Exception from g() My. Exception: Originated in g() at Inheriting. g(Inheriting. java: 20) at Inheriting. main(Inheriting. java: 29)
Criando suas próprias exceções class My. Exception 2 extends Exception { public My. Exception 2() {} public My. Exception 2(String msg) { super(msg); } public My. Exception 2(String msg, int x) { super(msg); i = x; } public int val() { return i; } private int i; }
public class Inheriting 2 { public static void f() throws My. Exception 2 { System. out. println( "Throwing My. Exception 2 from f()"); throw new My. Exception 2(); } public static void g() throws My. Exception 2 { System. out. println( "Throwing My. Exception 2 from g()"); throw new My. Exception 2("Originated in g()"); } public static void h() throws My. Exception 2 { System. out. println( "Throwing My. Exception 2 from h()"); throw new My. Exception 2( "Originated in h()", 47); } public static void main(String[] args) { try { f(); } catch(My. Exception 2 e) { e. print. Stack. Trace(); } try { g(); } catch(My. Exception 2 e) { e. print. Stack. Trace(); } try { h(); } catch(My. Exception 2 e) { e. print. Stack. Trace(); System. out. println("e. val() = " + e. val()); } } }
Criando suas próprias exceções Throwing My. Exception 2 from f() My. Exception 2 at Inheriting 2. f(Inheriting 2. java: 22) at Inheriting 2. main(Inheriting 2. java: 34) Throwing My. Exception 2 from g() My. Exception 2: Originated in g() at Inheriting 2. g(Inheriting 2. java: 26) at Inheriting 2. main(Inheriting 2. java: 39) Throwing My. Exception 2 from h() My. Exception 2: Originated in h() at Inheriting 2. h(Inheriting 2. java: 30) at Inheriting 2. main(Inheriting 2. java: 44) e. val() = 47
Criando suas próprias exceções class Simple. Exception extends Exception { }
Especificação de Exceções
Especificação de Exceções void f() throws too. Big, too. Small, div. Zero { //. . . } void f() { //. . . }
EXCEÇÕES PADRÃO DO JAVA
Exceções padrão do Java Throwable: w Error w Exception
Exceções padrão do Java http: //java. sun. com
Exceções padrão do Java Todas as classes herdam de java. lang. Exception Mas nem todas estão definidas em java. lang. Por exemplo: java. io. IOException
Exceções padrão do Java Runtime. Exception
Exceções padrão do Java: Runtime. Exception if(t == null) throw new Null. Pointer. Exception();
Exceções padrão do Java: Runtime. Exception public class Never. Caught { static void f() { throw new Runtime. Exception("From f()"); } static void g() { f(); } public static void main(String[] args) { g(); } }
Exceções padrão do Java: Runtime. Exception java. lang. Runtime. Exception: From f() at Never. Caught. f(Never. Caught. java: 9) at Never. Caught. g(Never. Caught. java: 12) at Never. Caught. main(Never. Caught. java: 15)
Exceções padrão do Java: Runtime. Exception Se uma Runtime. Exception chega ao main sem ser capturada, print. Stack. Trace( ) é chamado, e o programa sai.
Exceções padrão do Java: Runtime. Exception Uma Runtime. Exception significa um erro de programação: w w Um erro do programador cliente, que passou um ponteiro nulo, causando uma Null. Pointer. Exception Um erro seu, que não verificou se estava acessando um índice válido do vetor, e causou uma Array. Index. Out. Of. Bounds. Exception
Finally
w Frequentemente existe algum trecho de código que deve ser executado independente de uma exceção ter ou não ter sido disparada. w Problema: se o método alocou um recurso e uma exceção foi disparada, o recurso pode não ter sido liberado.
w Apesar de Java possuir coleta de lixo, pode ser necessário retornar algum recurso não relacionado a memória para seu estado original. w Exemplos: fechar um arquivo, fechar uma conexão de rede, redesenhar algum componente na tela, etc.
w Em Java: n finally: indica o trecho de código que sempre será executado. Formato básico: try { // Código } catch(Classe. De. Excecao e) { // Manipulador da exceção } finally {. . . // Código que será } // executado sempre
w Exemplo: em quaisquer circunstâncias, Java executará g. dispose(). Graphics g = image. get. Graphics(); try {. . . } catch(IOException e) { terminou = true; } finally { g. dispose(); }
w Possibilidades de execução do finally: n n n O código não dispara exceções: tudo o que estiver no try e, em seguida, no finally, é executado. O código dispara uma exceção que é capturada por um catch: tudo o que estiver no try até a exceção ser disparada é executado. Depois, executa o código do catch e, por fim, o finally. O código dispara uma exceção que não é capturada por nenhum catch: tudo o que estiver no try até a exceção ser disparada é executado. Depois, executa o código do finally.
Restrições a exceções
w Existe uma tendência a se abusar de exceções. w Exceções podem diminuir muito o desempenho do código. w Algumas dicas devem ser seguidas quando se está usando exceções.
w Testes simples não devem ser substituídos por manipulação de exceções. w Exemplo: tentar desempilhar 1. 000 de vezes uma pilha vazia. 1)if (!pilha. empty()) pilha. pop(); ---> 6 s 2)try { pilha. pop(); } ---> 64 s catch(Empty. Stack. Exception e){. . . } w Conclusão: use exceções apenas para circunstâncias excepcionais.
w Não microgerencie exceções. w Exemplo: gravar os elementos de uma pilha num arquivo. for (i = 0; i < 100; i++) { try { n = pilha. pop(); } catch(Empty. Stack. Exception s){. . . } try { out. write. Int(n); } catch(IOException e){. . . } } w Se a pilha estiver vazia, continuará vazia; se houver um erro no arquivo, ele não sumirá.
w Faz mais sentido colocar toda a operação no try { for (i = 0; i < 100; i++) { n = pilha. pop(); out. write. Int(n); } catch(IOException e) {. . . } catch(Empty. Stack. Exception s){. . . } } w Conclusão: o código fica mais limpo, garantindo a premissa básica.
w Não bloqueie exceções. w Exemplo: carregar uma imagem de arquivo. Image load. Image(String nomearq) { try { // Inúmeras linhas } // de código catch (Classe. De. Excecao e) {} } w Conclusão: o programador deve se esforçar para gerenciar exceções corretamente.
Construtores
import java. io. *; class Input. File { private Buffered. Reader in; Input. File(String fname) throws Exception { try { in = new Buffered. Reader(new File. Reader(fname)); // Other code that might throw exceptions } catch(File. Not. Found. Exception e) { System. out. println( "Could not open " + fname); // Wasn't open, so don't close it throw e; } catch(Exception e) { // All other exceptions must close it try { in. close(); } catch(IOException e 2) { System. out. println( "in. close() unsuccessful"); } throw e; } finally { // Don't close it here!!! } } String get. Line() { String s; try { s = in. read. Line(); } catch(IOException e) { System. out. println( "read. Line() unsuccessful"); s = "failed"; } return s; } void cleanup() { try { in. close(); } catch(IOException e 2) { System. out. println( "in. close() unsuccessful"); } } }
Construtores public class Cleanup { public static void main(String[] args){ try { Input. File in = new Input. File("Cleanup. java"); String s; int i = 1; while((s = in. get. Line()) != null) System. out. println(""+ i++ + ": " + s); in. cleanup(); } catch(Exception e) { System. out. println( "Caught in main, e. print. Stack. Trace()"); e. print. Stack. Trace(); } } }
Contrutores String get. Line() throws IOException { return in. read. Line(); }
Casamento de Exceções
Casamento de Exceções class Annoyance extends Exception {} class Sneeze extends Annoyance {} public class Human { public static void main(String[] args) { try { throw new Sneeze(); } catch(Sneeze s) { System. out. println("Caught Sneeze"); } catch(Annoyance a) { System. out. println("Caught Annoyance"); } } }
Casamento de Exceções try { throw new Sneeze(); } catch(Annoyance a) { System. out. println("Caught Annoyance"); } catch(Sneeze s) { System. out. println("Caught Sneeze"); }
Conclusão
Conclusão Use exceções para: 1) Consertar o problema e chamar o método que causou a exceção de novo 2) Contornar o erro e continuar sem tentar o método novamente 3) Calcular algum resultado alternativo em vez daquele que o método deveria produzir 4) Fazer o que for possível no contexto atual e lançar a mesma exceção para o contexto superior 5) Fazer o que for possível no contexto atual e lançar uma exceção diferente para o contexto superior 6) Terminar o programa 7) Simplificar. Se seu esquema de exceções complica as coisas, então ele será ruim para ser usado 8) Tornar sua biblioteca e seu programa mais seguros
- Slides: 61