Tratamento de Exceções Java Avançado Tratamento de Exceções Roberto Vedoato [email protected] Introdução Princípios do tratamento de exceções em Java Cláusula try Cláusula catch Cláusula finally Hierarquia de exceções em Java Definição de classes de exceção Considerações finais Tratamento de Exceções Conceito de Exceções 2 Exemplo O termo exceção (do inglês exception) é uma abreviatura da frase “exceptional event”, indica que ocorreu uma condição anormal, um problema, durante a execução de um programa Definição formal: um evento que ocorre durante a execução de um programa que quebra o fluxo normal dessa execução São tipos de erros que podem ser tratados e que o sistema pode se recuperar do mau funcionamento que o causou Na simples função para ler um arquivo do disco para a memória lerArquivo{ abrir o arquivo; determinar seu tamanho; alocar memória; ler o arquivo para a memória; fechar o arquivo; } O que ocorre se: Tratamento de Exceções 3 O arquivo não puder ser aberto ? Não for possível determinar o tamanho do arquivo ? Não for possível alocar a quantidade total de memória ? A leitura falhar ? O arquivo não puder ser fechado ? Tratamento de Exceções 4 Tratamento de Exceções Princípios do tratamento de exceções em Java Quando problemas ocorrem não podemos simplesmente abortar um programa Devemos ter códigos mais robustos e seguros, com uma melhor tolerância a falhas Comumente o código de tratamento de exceções é intercalado ao longo do código do sistema em si, através de estruturas condicionais (if-else), diminuindo a legibilidade e dificultando a manutenção do código Tratamento de Exceções 5 Quando um método que detecta um erro é incapaz de lidar com ele, o método é terminado e “lança” uma exceção (throw an exception) para o sistema encontrar um código para o tratar A busca inicia na chamada do método onde o erro aconteceu. Se eles não tiverem condições de lidar com o erro, o sistema continua ao longo da pilha de chamadas, até encontrar o código apropriado Ao ser encontrado o código correto, o sistema “pega” o objeto exceção e executa o tratamento (catch the exception) Tratamento de Exceções Tratamento de Exceções 6 Cláusula try - Delimitando Princípios do tratamento de exceções em Java Java oferece estruturas (try-catch) que permitem capturar e tratar exceções separadamente, fora da linha principal de execução do programa Em Java as exceções são objetos especiais, derivados da classe Exception, hierarquia Throwable, que carregam informação sobre o tipo de erro detectado 7 Para capturar uma exceção o primeiro passo é delimitar o código que pode gerar exceções dentro de um mesmo contexto, através da causula try Sintaxe: try { Comandos que possam gerar exceção } Tratamento de Exceções 8 Cláusula catch - Capturando Exemplo ParImpar A seguir, a instrução catch define qual o código que irá ser executado, dependendo da exceção gerada Sintaxe: catch (SomeThrowableObject variavel) { Ações de tratamento } O bloco catch é muito parecido com um método, identifica o tipo de exceção que ele trata através do seu parâmetro único Apenas o primeiro bloco que diz tratar a exceção lançada é executado. Os outros blocos catch são ignorados Tratamento de Exceções import java.io.*; public class ParImpar { public static void main (String args[]) { int num; num = Integer.parseInt(args[0]); if (num % 2) == 0 System.out.println(“Número par"); else System.out.println(“Número impar"); } } Se o argumento não for fornecido, o que acontece? 9 Exemplo ParImpar Tratamento de Exceções 10 Exemplo ParImpar Ocorre uma exceção da classe java.lang.ArrayIndexOutOfBoundsException public class ParImpar { public static void main (String args[]) { int num; try { num = Integer.parseInt(args[0]); if (num % 2) == 0 System.out.println(“Número par"); else System.out.println(“Número impar"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Não foi fornecido um argumento."); } catch (java.lang.NumberFormatException e) { System.out.println("Não foi fornecido um inteiro válido."); } } public class ParImpar { public static void main (String args[]) { int num; if (args.length > 0) { num = Integer.parseInt(args[0]); if (num % 2) == 0 System.out.println(“Número par"); else System.out.println(“Número impar"); } else { System.out.println("Não foi fornecido um argumento inteiro"); } } É a solução ideal? Um simples programa para saber se um número é par ou impar, onde o número é passado como argumento Considere agora que o argumento não seja um número inteiro Tratamento de Exceções 11 Tratamento de Exceções 12 Clausula finally Clausula finally – Exemplo Clássico Uma clausula finally está associada a uma cláusula try Sintaxe: try { ... } finally { ... } try { // abre um arquivo // gera exceções com arquivos } catch (ExceçaoArquivo e) { // tenta recuperar arquivo e informações perdidas } finally { // fecha arquivo } O código contido na cláusula finally é sempre executado ocorrendo ou não erros dentro do trecho delimitado pela cláusula try Tratamento de Exceções Particularmente interessante quando certos recursos do sistema ou estruturas de dados devem ser liberadas, independentemente de sua utilização. Ex: fechar um arquivo ou conexão com o banco de dados 13 Hierarquia de exceções em Java Tratamento de Exceções Hierarquia de exceções em Java Error Exceções são objetos derivados de Throwable Exceptions são exceções explícitas que devem ser capturadas e tratadas Erros e RuntimeExceptions são exceções implícitas que não precisam ser capturadas Tratamento de Exceções Não verificadas em tempo de compilação Subclasses de RuntimeException representam erros de lógica de programação que devem ser corrigidos (podem, mas não devem ser capturadas: erros devem ser corrigidos) Exception 15 Não verificados em tempo de compilação Subclasses de Error não devem ser capturadas (são problemas de sistema particularmente sérios que não podem ser contornados, onde a recuperação é impossível ou indesejável) RuntimeException 14 Verificadas em tempo de compilação (exceto as subclasses de RuntimeException) Compilador exige que sejam ou capturadas ou declaradas pelo método que potencialmente as provoca Tratamento de Exceções 16 Hierarquia de exceções em Java Hierarquia de exceções de Java Através do conceito de herança, podemos tratar exceções por grupos. Exemplo: catch (ArrayIndexOutOfBoundsException e) { ... } IndexOutOfBoundsException é uma subclasse de RuntimeException, que por sua vez, é uma subclasse de Exception derivada de Throwable Ela possui 2 subclasses cada uma para um erro específico: ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException Tratamento de Exceções Ou caso for conveniente, tratá-las pelo grupo. Exemplo: Baseados na hierarquia, temos a superclasse de exceção IndexOutOfBoundsException, que representa qualquer exceção que pode acontecer com ao tentar acessar um índice fora dos limites, seja de string, array ou vetor. O tratamento seria catch (IndexOutOfBoundsException e) { ... } 17 Hierarquia de exceções em Java Poderíamos tratá-las uma a uma. Exemplo: Tratamento de Exceções 18 Classe Exception – Principais Métodos Ainda considerando o conceito de herança, as exceções herdam um série de métodos da classe Throwable. Um dos mais utilizados é o getMessage(), que serve para mostrar qual a mensagem de erro. Ao consultar a API, verifique que muitas vezes, métodos não informam apenas argumentos e retorno, mas também exceções que podem ocorrer ao utilizálos. Devemos lidar com elas! A clausula throws declara as exceções que podem ser disparadas por métodos ou construtores Construtores de Exception Métodos de Exception Tratamento de Exceções 19 Exception () Exception (String message) Exception (String message, Throwable cause) String getMessage() - Retorna mensagem passada pelo construtor Throwable getCause() - Retorna exceção que causou esta exceção String toString() - Retorna nome da exceção e mensagem void printStackTrace() - Imprime detalhes (stack trace) sobre exceção Tratamento de Exceções 20 Definindo Classes de Exceção Disparando - throw Exceções especiais podem ser criadas em adição às existentes ampliando as possibilidades de tratamento de erro (basta criar uma classe que estenda a hierarquia Exception). Exemplo: a classe DivisaoPorZero estende ArithmeticException pois a divisão por zero ocorre durante uma operação matemática Usando a classe DivisaoPorZero, num método qualquer (metodo1) de uma classe qualquer (Classe1) public class Classe1 { … public double metodo1(int num, int den) throws DivisaoPorZero { if (den == 0) throw new DivisaoPorZero(“Na classe Classe1”); … public class DivisaoPorZero extends ArithmeticException { // construtor com mensagem de parametro public DivisaoPorZero(String msg) { super(msg); } Sendo um objeto, a exceção precisa ser criada com new A instrução throw dispara uma exceção, isto é, lança um objeto exceção } Tratamento de Exceções 21 Declarando - throws 22 Capturando a nova exceção A clausula throws declara as exceções que podem ser disparadas por métodos ou construtores Indica que o método pode provocar exceções do tipo declarado (ou de qualquer subtipo) Tratamento de Exceções … Classe1 x = new Classe1(); try { resultado = x.metodo1(4,0); } catch (DivisaoPorZero e) { System.out.println(“Impossível dividir por zero”); } … A declaração abaixo declara que o método pode provocar qualquer exceção (não faça isto!) public void m() throws Exception {...} Métodos sobrepostos não podem provocar mais exceções que os métodos originais Tratamento de Exceções Em um programa bastaria usar a Classe1 da seguinte maneira que essa nova exceção seria disparada e capturada 23 Tratamento de Exceções 24 Repassando uma Exceção Considerações Finais Às vezes, após capturar uma exceção, é desejável lançá-la novamente para que outros métodos lidem com ela Exemplo: Utilizamos tratamento de exceções: Em situações onde o sistema pode se recuperar do mau funcionamento que causou a exceção. Exemplos: public void metodo() throws ExcecaoSimples { try { // instruções } catch (ExcecaoSimples e) { // faz alguma coisa para lidar com a exceção throw e; // repassa a exceção } Tratamento de Exceções Em grandes projetos, para uniformizar o tratamento, etc. Tratamento de Exceções 26 Considerações Finais Vantagens sobre as linguagens tradicionais: métodos da API Java 25 Considerações Finais Para processar exceções de componentes que não são projetados para tratar as exceções diretamente. Por exemplo: acessar vetores com índice inválidos esgotamento de memória divisão por zero parâmetros inválidos de métodos Separar o gerenciamento de erros do código comum Propagação de erros, que permite que se crie uma classe especializada apenas no gerenciamento destes eventos É possível agrupar erros por tipo, tratando-os de uma vez Características Tratamento de Exceções 27 A ocorrência de erros no Java é sinalizada através de exceções, isto é, objetos especiais que carregam informação sobre o tipo de erro detectado. São objetos derivados de Throwable Æ Exception Estrutura: try-cath e try-cath-finally para lidar com elas. Desviando a execução automaticamente para uma rotina designada para o tratamento específico deste erro. A cláusula finally é sempre executado ocorrendo ou não erros dentro do trecho delimitado pela cláusula try. A ordem das cláusulas catch importa, pois mais de uma pode lidar com a exceção, e ela é tratada na primeira cláusula catch compatível Tratamento de Exceções 28 Exercícios 1. Os códigos abaixo são válidos? try { try { ... ... } } finally { ... ... } 2. Disparar uma exceção pode terminar a execução de um programa? 3. Quais as exceções que serão capturadas pelo bloco abaixo? Há alguma coisa errada com esses blocos? O código compila? ... } catch (Exception e) { ... } catch (ArithmeticException a) { ... } Tratamento de Exceções 29