Estudo sobre tratamento de exceções em Java.
Cláusula try catch finally;
Claúsula throws;
Hierarquia de exceções;
Exceções verificadas e não cerificadas, catch-or-declare;
Encadeamento de exceções;
Criação de exceções personalizadas.
1. Tratamento de Exceções em Java
Uma exceção é uma indicação de um problema incomum que ocorreu durante a execução de um programa.
Com o tratamento de exceções é possível continuar a execução do programa (sem encerrá-lo) depois de lidar
com o problema. Programas robustos e tolerante a falhas são aqueles que podem lidar com problemas à
medida que surgem e continuar executando.
O tratamento de exceções aprimora a tolerância a falhas de um programa.
Mesclar o código de tratamento de erro com o código do programa pode degradar seu desempenho porque
realizaria testes frequentes para determinar se tarefas que podem gerar erros foram executadas corretamente a
fim de que a próxima tarefa possa ser executada.
O tratamento de exceções permite separar o código do tratamento do erro do código principal de execução,
aprimorando a clareza do programa e melhorando sua capacidade de modificação.
O tratamento de exceções é projetado para processar erros síncronos, o tratamento de exceções NÃO é
projetado para processar problemas associados a eventos assíncronos, tais como E/S de disco, chegada de
mensagem de rede, cliques de mouse ou pressionamento de teclas, que ocorrem paralelamente ao fluxo de
controle do programa e independentemente dele.
Pode ser difícil incluir um tratamento de exceções depois que um sistema foi implementado, portanto é preferível
incorporar a estratégia de tratamento de exceções ao sistema desde o design no princípio do projeto.
Hierarquia de exceções em Java
Iniciada na classe Throwable (subclasse de Object) é seguida de duas subclasses, Exception e Error.
A classe Exception e suas subclasses representam situações excepcionais que podem ocorrer em um
programa e serem capturadas e tratadas pelo aplicativo.
A classe Error e suas subclasses representam situações anormais que ocorrem na JVM e não devem ser
capturados pelos aplicativos. Normalmente não é possível que aplicativos se recuperem de erros.
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
2. Exceções verificadas e Exceções não verificadas
Na hierarquia de Exception, o tipo de uma exceção determina se ela é verificada ou não verificada.
Exceções não verificadas costumam ser causadas por deficiências no código do programa.
Exceções verificadas são causadas por condições que estão fora do controle do programa.
Subclasses (diretas ou indiretas) de RuntimeException são exceções não verificadas.
Subclasses que herdam de Exception mas não de RuntimeException são exceções verificadas.
O programador precisa lidar com exceções verificadas, isso resulta em código mais robusto do que aquele que
seria criado se fosse possível simplesmente ignorá-las. Por conta disso o requisito catch-or-declare é
obrigatório. Ao contrário das exceções verificadas, o compilador não verifica se uma exceção não verificadas é
capturada ou declarada, pois é possível impedir a ocorrência de tais exceções pela codificação adequada.
Todas as subclasses que herdam de Exception são exceções verificadas exceto as que herdam de
RuntimeException.
Instrução try catch e Cláusula throws
O compilador impõe um requisito catch-or-declare (capture ou declare) às exceções verificadas.
Como as exceções verificadas devem ser capturadas ou declaradas (catch-or-declare), o compilador verifica
toda chamada de método para determinar se o mesmo lança exceções verificadas. Se lançar, checa se a exceção
é capturada por uma instrução try catch ou declarada em uma cláusula thows. Se o requisito capture ou
declare não for satisfeito, o compilador emite uma mensagem de erro indicando que a exceção deve ser
capturada ou declarada.
Classes que herdam de Error são consideradas como não verificadas.
A Classe Throwable oferece os métodos getMessage(), que retorna uma mensagem descrevendo detalhes do
problema ocorrido, e printStackTrace(), que envia para o fluxo de erro o rastreamento da pilha de
execução indicando onde aconteceu o problema. Isso é frequentemente útil no processo de depuração.
Tratamento de Exceções
Clausula throws
Uma cláusula throws especifica quais exceções um método pode lançar, um método pode lançar exceções das
classes listadas em sua cláusula throws ou de suas subclasses.
Métodos que podem lançar exceções são definidos com a palavra-chave throws que especifica tais exceções
declarando entre a lista de parâmetros e o corpo do método uma lista de exceções separadas por vírgulas que
o método pode lançar caso ocorram.
Caso haja um erro, o método encerra sua execução e a JVM lança um objeto do tipo especificado na cláusula
que será capturado pelo bloco catch cujo tipo especificado no parâmetro seja correspondente e exibirá
informações básicas sobre a exceção invocando implicitamente seu método toString().
A cláusula throws não deve ser confundida com a instrução throw,utilizada para lançar exceções.
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
3. Instrução throw
Lançando exceções com a instrução throw
Assim como as exceções lançadas pela JVM, é possível lançar exceções com a instrução throw , executada para
indicar para os aplicativos que uma exceção ocorreu.
throw new Exception();
Uma instrução throw especifica um objeto a ser lançado e seu operando pode ser de qualquer classe derivada
de Throwable.
Instrução try catch [finally]
Bloco try
As instruções que podem lançar algum tipo de exceção (causar erro) devem ser colocá-las dentro do bloco try,
caso não haja erro, serão são executadas normalmente e o controle do programa segue para a primeira
instrução depois do último bloco catch ou para a execução do bloco finally , se houver.
Caso ocorra alguma exceção, o código do bloco try não é executado e um objeto representando a exceção é
criado e lançado a fim de ser capturado pelo bloco catch correspondente.
Será executado o primeiro bloco catch cujo tipo de parâmetro corresponder (ou ser uma superclasse) à
exceção ocorrida e lançada pelo bloco try.
Dentro do bloco try, o método lança um objeto exceção, um manipulador catch captura a exceção e dá o
tratamento necessário.
Exceções podem ser lançadas a partir do código do bloco try, por chamadas de métodos iniciadas no bloco
try (mesmo que aninhados) ou a partir da JVM à medida que executa os bytecodes.
Modelo de terminação de Tratamento de Exceções do Java
No Java, depois que uma exceção é tratada, o controle do programa não retorna ao ponto de lançamento
porque o bloco try expirou e suas variáveis locais foram perdidas.
Algumas linguagens utilizam o Modelo de Retomada de Tratamento de Exceções em que o controle é retomado
logo depois do ponto de lançamento.
Com o tratamento de exceções, caso o usuário cometa um erro na inserção de dados, o programa pode
capturar esse erro e tratá-lo.
É possível oferecer ao usuário a opção de que ele insira a entrada novamente com uma condição num laço.
Dentro do(s) bloco(s) catch { }, a rotina Scanner.nextLine() descarta a entrada e o usuário pode inseri-la
novamente. Caso a entrada seja correta a condição do laço é configurada como false dentro do bloco try { } e o
programa segue normalmente.
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
4. Bloco catch
É possível tratar uma determinada exceção, todas as exceções, as exceções de um certo tipo ou exceções de
um grupo de tipos relacionados numa hierarquia de classes.
Pelo menos um bloco catch obrigatório e um bloco finally opcional deve seguir um bloco try .
Cada bloco catch pode ter apenas um único parâmetro.
O parâmetro de exceção do bloco catch especifica que tipo de exceção o handler pode processar.
Utilizar um nome de parâmetro de exceção que reflita o seu tipo, em oposição a variável 'e', promove clareza e é
uma boa prática de programação.
catch(ArithmeticException divisaoPorZero) {//...}
catch(InputMismatchException tipoIncompativel) {//...}
A ordem dos blocos catch é importante
Caso haja múltiplos blocos catch que correspondam a um tipo particular de exceção, somente o primeiro bloco
catch correspondente executará caso ocorra a exceção.
Não podemos colocar uma superclasse (Exception) antes de uma subclasse, pois isso indicaria uma situação
onde teríamos um tratamento de erro que nunca seria alcançado, já que a superclasse não deixaria o teste ser
feito capturando todas as exceções de forma generalizada. Em contrapartida, capturar a superclasse no último
bloco catch garante que os objetos de todas as subclasses sejam capturados.
Posicionar um bloco catch para tipo superclasse após todos os outros de subclasse assegura que todas as
exceções de subclasse sejam por fim capturadas.
Como qualquer bloco de código, quando um bloco try termina, suas variáveis locais saem de escopo e não são
mais acessíveis. Logo, as variáveis locais de um bloco try não são acessíveis nos seus blocos catch
correspondentes. O mesmo ocorre com as variáveis locais do bloco catch , quando um bloco catch termina,
as variáveis locais declaradas também saem de escopo e são destruídas.
Bloco finally
O bloco finally (opcional) deve ser colocado após o último bloco catch. Sua utilização é indicada para
liberação de recursos adquiridos num bloco try ou catch.
Os programas que obtêm certos tipos de recursos devem retorná-los explicitamente ao sistema, a fim de evitar
"vazamento de recursos", como vazamento de memória (apesar do Java ter coleta automática de lixo), arquivos
ou conexões de BD ou conexões de rede que não são fechadas adequadamente.
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
5. O bloco finally executa independentemente de uma exceção ser lançada.
Caso a exceção seja capturada, o comando passa para o bloco finally depois do último catch . Caso a
exceção não seja capturada, o comando passa para o bloco finally depois do try , nessas duas opções os
recursos adquiridos em cada bloco são liberados pela instrução dentro do bloco finally .
Capturando exceções de subclasse
Se um handler catch capturar objetos de exceção tipo superclasse, também pode capturar objetos de
subclasse dessa classe. Caso o tratamento das exceções exija processamento diferente, é interessante capturar
cada tipo de subclasse individualmente.
Capturar exceções relacionadas com um handler tipo superclasse só faz sentido se o tratamento for o mesmo
para todas as subclasses.
Exceções não tratadas
Uma exceção para a qual não há nenhum bloco catch correspondente é uma exceção não capturada.
Quando um método detecta um problema e é incapaz de tratá-lo, exceções são lançadas pela JVM e o
rastreamento de pilha é exibido. O tipo de exceção é especificado e o rastreamento de pilha inclui o caminho da
execução que resultou na exceção, método por método. A linha superior da cadeia de chamadas indica o ponto
de lançamento inicial onde a exceção ocorreu.
Cada linha do rastreamento de pilha contém pacote.Classe.metodo.arquivo.numDaLinha
Caso um programa tenha múltiplas Threads, uma exceção não capturada encerrará apenas a Thread em que
ocorreu a exceção.
Exceções encadeadas
Quando um método responde a uma exceção lançando um tipo de exceção diferente que é específica do
aplicativo em uso, as informações da exceção original são anexadas às informações da nova exceção.
Exceções encadeadas fornecem mecanismos para empacotar as informações da exceção original e do
rastreamento de pilha, permitindo a um objeto exceção manter informações de rastreamento de pilha
completas a partir da exceção original.
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
6. public class ExcecoesEncadeadas {
public static void main( String[] args ) {
try {
method1(); // call method1
}
catch ( Exception excC ){ // exceptions thrown from method1
exc1.printStackTrace();
}
} // main
public static void method1() throws ExceptionC {
try {
method2(); // throw exceptions back to main
}
catch ( Exception excB ){ // exception thrown from method2
throw new ExceptionC( "Exception thrown in method1", excC );
}
} // method1()
public static void method2() throws ExceptionB {
try {
method3(); // throw exceptions back to method1
}
catch ( Exception excA ){ // exception thrown from method3
throw new ExceptionB( "Exception thrown in method2", excB );
}
} // method2()
public static void method3() throws ExceptionA {
// throw Exception back to method2
throw new ExceptionA( "Exception thrown in method3" );
} // method3()
}//class
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
7. Criando uma nova exceção
Para criar uma nova classe de exceção, esta deve estender uma classe de exceção existente, isso assegura que
ela possa ser utilizada com o mecanismo de tratamento de exceções do Java. Ao definir seu próprio tipo de
exceção, estude as Classes de exceção existente na API do Java e tente estender uma Classe de exceção
relacionada.
Uma nova Classe de exceção deve ser uma exceção verificada (estende Exception, mas não RuntimeException)
caso a exceção precise ser tratada ou deve ser uma exceção não verificada (estender RuntimeException) se for
possível ignorar a exceção.
Por convenção todos os nomes de Classes de exceção devem terminar com a palavra Exception.
Uma Classe de exceção pode conter campos e métodos.
Uma nova Classe de exceção típica contém "somente quatro construtores":
1. Um construtor que não recebe nenhum argumento e passa uma mensagem de erro padrão String para
o construtor da superclasse;
2. Um construtor que recebe uma String como mensagem de erro personalizada e a passa para o
construtor da superclasse;
3. Um construtor que recebe uma String como mensagem de erro personalizada e um throwable (para
exceções encadeadas) e passa ambos para o construtor da superclasse;
4. Um construtor que recebe um throwable (para exceções encadeadas) e o passa para o construtor da
superclasse;
Procedimento para criar uma nova exceção
1. Cria-se uma nova Classe de Exceção estendendo-se uma Classe de exceção existente (Exception);
2. Implementa-se essa Classe com quatro opções de construtores típicos de Classes de exceções;
3. Cria-se uma Classe de testes para colocar o código do programa dentro de uma instrução try catch;
4. Coloca-se como argumento de um bloco catch { } um objeto do tipo ExcecaoCriada e dentro do bloco
implementa-se o tratamento necessário ao erro;
Pré-condições e Pós-condições
São os estados esperados antes e depois da execução de um método, respectivamente.
Uma pré-condição descreve restrições nos parâmetros e deve ser verdadeira quando um método é invocado.
Caso não sejam satisfeitas, o comportamento do método será indefinido.
Uma pós-condição é verdadeira depois que um método retorna com sucesso. Descrevem as restrições sobre o
valor de retorno e quaisquer outros efeitos colaterais que o método possa apresentar.
Se as pré-condições e pós-condições não forem satisfeitas, os métodos costumam lançar exceções.
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet
8. Exemplo:
Wilson Ventura Júnior - Análise e Desenvolvimento de Sistemas - Instituto Infnet