...mais sobre exceções em Java
Autor: Luciano da Cunha | Publicado: 2012-02-07T16:29:00-08:00

Algumas observações:

O tipo da exceção declarada no catch deverá ser compatível com a exceção esperada. Do contrário, o Java alertará que o erro não está sendo tratado. (Exceções verificadas).

Perceba também que existe uma hierarquia permitida para declaração de vários catch's. Caso seja necessário declarar vários catch's procure começar com as classes filhas e posteriormente ir para as classes mais genéricas.

Resumo das Exceptions.


Object
 |
 |-- ...
 |
 |-- Throwable
   |
   |-- Error (Não verificadas)
   |  |
   |  |-- ...
   |
   |-- Exception
     |
     |-- ... (Verificadas)
     |
     |-- RuntimeException (Não verificadas)
        |
        |-- ...

Veja em: http://download.oracle.com/javase/6/docs/api/java/lang/package-tree.html

É preciso importar a classe da exceção utilizada, no caso de  exceções que não forem do pacote java.lang.

import java.io.*;

class TestException4{
 public static void main(String[] args){

  try{

   throw new FileNotFoundException();

   //throw new IOException();

  // Procure ir "afunilando" a captura de exceções...
  } catch(FileNotFoundException f){

   f.printStackTrace();

  // IOException é superclasse de FileNotFoundException, por isso, caso
  // necessária deve ser inserida posteriormente...
  } catch(IOException i){

   i.printStackTrace();

  // .. a menos que não fizerem parte da mesma hierarquia direta.
  // RuntimeException não herda de IOException
  }catch(RuntimeException r){

   r.printStackTrace();

  }finally{

   System.out.println("...liberando recursos!");

  }

 }
}

..inverta os catch's acima para enteder melhor a necessidade da ordem de precedência.

&nbsp;
Tratando a exceção ou delegando o tratamento..Você pode ainda optar por tratar ou transferir o tratamento para um método chamador.

Caso opte por tratar, é só usar a estrutura try/catch/finally, caso não, terá que declarar na interface do método o tipo da exceção lançada. Desta forma, o processamento é interrompido e o controle é passado para o método chamador.

Observe o código abaixo.

class TestException2{

 public static void main(String[] args){

  try {

   System.out.println("...iniciando o método main!");

   testException1();

   //System.out.println("..tentando executar este código!");
   // nunca será executado.

  } catch(Exception e){

   System.out.println("..catch do main!");

  }

  // Graças ao tratamento que foi feito, conseguimos pelo menos terminar
  // a thread.
  System.out.println("..finalizando metodo main()");
 }

 static void testException1() throws Exception{

  testException2();
  System.out.println("..finalizando metodo testException1()");

 }

 static void testException2() throws Exception{

  try {

   testException3();

  } catch (Exception ex){

   ex.printStackTrace();

  } finally {

   System.out.println("..finalizando metodo testException2()");

  }

 }

 static void testException3() throws Exception{

  testException4();
  System.out.println("..finalizando metodo testException3()");

 }

 static void testException4() throws Exception{

  throw new Exception("Metodo 4");
  //System.out.println("..finalizando metodo testException4()");

 }

}

Em um sequência de chamadas de métodos, uma exceção é lançada no topo da pilha. O último método não trata a exceção passando o controle para o seu método chamador e assim sucessivamente. Note que antes de chegar no método main a  exceção é tratada, porém, o método (testException2) declara uma Exception, o que obriga a alguém, abaixo na pilha a se preocupar com um possível tratamento, mesmo que nenhuma exceção seja transferida.

Por fim, observe que nenhuma exceção foi transferida mesmo, pois o catch do main não foi processado. Mas como o método testException2 alertou sobre a Exception em potencial, e testException1 transferiu o tratamento, sobrou para main tratar.

&nbsp;
Personalizando suas ExceptionsEm alguns caso, você poderá ainda, criar suas próprias exceções.

E como tudo em Java é herança (ou interfaces, ;)) essa classe deverá herdar de um tipo existente de classes. Caberá ao programador decidir se o novo tipo será uma exceção ou erro. Caso exceção, se será verificada ou não.

Abaixo um pequeno exemplo demonstrando como criar classes de exceções.

class ExcecaoVerificada extends Exception{

 public ExcecaoVerificada(){}

 // Característica das exceptions possuir um método construtor que recebe uma
 // mensagem com informações sobre o problema.
 public ExcecaoVerificada(String message){

  super(message);

 }

}

class ExcecaoNaoVerificada extends RuntimeException {}

class TestExceptionVerificada {

 public static void main(String[] args){

  try{

   // Tratamento obrigatório.
   testExcecaoVerificada();

  } catch (ExcecaoVerificada e){

   System.err.println(e.getMessage());

  }

  // Para exceções não verificadas o tratamento é facultativo.
  testExcecaoNaoVerificada();

 }

 static void testExcecaoNaoVerificada() throws ExcecaoNaoVerificada{}

 static void testExcecaoVerificada() throws ExcecaoVerificada{

  // Lançando a exceção e passando um mensagem sobre ela.
  throw new ExcecaoVerificada("ExcecaoVerificada!!!");

 }

}