Desenvolvimento - Java

Manipulação de Exceções

Uma exception representa uma condição excepcional que altera o fluxo normal do programa. Quando um evento deste tipo ocorre no Java, uma exceção é lançada e a execução do programa é transferida para o código responsável por tratar esta exceção.

por Vanessa Sabino



Uma exception representa uma condição excepcional que altera o fluxo normal do programa. Quando um evento deste tipo ocorre no Java, uma exceção é lançada e a execução do programa é transferida para o código responsável por tratar esta exceção.

Este mecanismo de tratamento de exceções oferece várias vantagens. Através dele é possível isolar o código responsável pelo tratamento do erro em blocos separados, deixando o código principal mais limpo. Também é possível tratar erros similares com um único bloco de tratamento, eliminando código duplicado. Existe até a possibilidade de transferir o tratamento de uma exceção para outros métodos da pilha.

Para indicar a JVM qual código deve ser executado quando acontece uma exceção, são utilizados blocos try/catch. Dentro do try é colocado o código que pode gerar uma exceção, e a seguir são colocados um ou mais blocos catch, correspondentes às exceções que podem ocorrer. Os blocos catch devem estar logo em seguida do bloco try, e recebem o objeto da exceção como argumento, que sempre será de uma subclasse de Exception.

Exemplo:

Listagem 1: Estrutura de bloco try-catch

try {
// Código que pode gerar exceção
// Mais uma linha do bloco try
}
catch(PrimeiraException e1) {
// Código para tratar a exceção PrimeiraException
// Pode ser utilizados métodos para obter mais informações, tais como printStackTrace();
}
catch(SegundaException e2) {
// Código para tratar a exceção SegundaException
}
// Código normal começa aqui

As linhas 2 e 3 constituem a região que tentará ser executada pelo bloco try. As 6 e 7 tratam exceções do tipo PrimeiraException e a 10 do tipo SegundaException.

A execução inicia-se na linha 2, e se tudo ocorrer bem até a linha 3, o programa retomará na linha 12. Porém, se acontecer uma exceção do tipo PrimeiraException nas linhas 2 ou 3, a execução irá imediatamente para a linha 6, passará por todo o bloco catch até a linha 7 e então irá para a linha 12, em que volta a execução normal do código. Note que se uma exceção ocorrer na linha 2, o resto do bloco try não será executado. Desta forma, o código que é dependente de alguma operação de risco normalmente é agrupado dentro do bloco try. Por exemplo, na primeira linha você tenta abrir um arquivo, e dentro do mesmo bloco try tenta ler os dados deste arquivo. Se o Java não conseguir abrir o arquivo, irá diretamente ao bloco catch, não tentando ler os dados do arquivo.

Um bloco catch pode tratar de qualquer exceção que seja da mesma classe ou uma subclasse daquela declarada. As exceções que não são tratadas em blocos catch correspondentes a onde foram ocasionadas são passadas para o método anterior da pilha. Esse propagação ocorre sucessivamente até que algum método faça o catch ou até passar do main, chegando a JVM, que pára a aplicação e mostra a stack trace no output padrão.

É possível fazer um bloco catch para uma exceção específica e outro para todas as outras subclasses de uma determinada Exception. Porém, é necessário que o catch mais específico

(subclasse) apareça antes que o catch mais genérico (superclasse). Caso contrário o programa não irá compilar, apresentando uma mensagem de erro dizendo que a exceção já é tratada anteriormente.

O bloco finally pode aparecer logo após o try/catch. Nele fica o código que deve sempre ser executado, ocorrendo uma exceção ou não. Um bom uso é para liberar recursos que são utilizados no try (fechar um arquivo, a conexão com banco de dados, etc). O finally é executado sempre, até mesmo se existir um retorno do método return) dentro do try. Ele só não é executado se a JVM for desligada, através de um System.exit() ou um erro irreversível. Quando ocorre uma exceção, ele é executado logo após o catch, caso contrário, logo após o try.

Tanto a cláusula finally como a catch são opcionais, porém é necessário ter pelo menos uma delas para cada bloco try. A classe Exception é uma subclasse de Throwable, que provê alguns métodos muito úteis para obter informações sobre uma exceção, tais como o printStackTrace(). Outra subclasse de Throwable é a Error.

Errors e RuntimeExceptions são considerados uncheked, portando o compilador não obriga que exista tratamento para eles. Erros normalmente representam situações críticas, que não deveriam acontecer, como por exemplo acabar a memória da JVM. Já RuntimeExceptions (que são uma subclasse de Exception) indicam erros de programação ou condições especiais, difíceis de serem tratadas. As outras Exceptions costumam indicar que uma condição necessária para a execução de um programa não está presente, como por exemplo um recurso não disponível. Para todas as subclasse de Throwable é possível utilizar o throw/throws e o catch.

As exceções que um método lança precisam ser declaradas através da palavra throws, caso sejam do tipo checked. Isso não significa que ele obrigatoriamente irá lançar a exceção, apenas que isso pode acontecer. Se o método não faz o tratamento de uma exceção que ele recebe, também será necessário declará-la para passá-la adiante ela pilha.

Exemplo:

Listagem 2: Declaração de método com especificação das exceções geradas

void metodo() throws UmaException, DuasException {
// código do método
}

Cada método precisa tratar todas as exceções (checked) através de métodos catch, ou então listar em sua declaração cada exceção que não é tratada. Para repassar uma exceção que é recebida em uma cláusula catch também é necessário que ela seja declarada no método.

Para criar sua própria exceção basta estender a classe Exception, da seguinte forma:

Listagem 3: Sintaxe de declaração de nova exceção

class MinhaException extends Exception { }

A nova exceção criada deverá obedecer às regras de manipulação de exceções, sendo tratada ou lançada ao próximo método.

Vanessa Sabino

Vanessa Sabino