Pesquisar este blog

segunda-feira, 8 de abril de 2013

Tratamento de erros e Exceções em Java


Exceções e Erros:

Throwable:

Em java temos uma interface chamada Throwable, esta interface é quem determina quais classes podem ser "lançadas" , através do uso da palavra chave throw, no código. Existem duas classes básicas que implementam Throwable, são elas Error (Erro) e Exception (Exceção).

Erros:

Um erro acontece quando há um sério problema com o nosso código, algo que a nossa aplicação não conseguirá tratar, por exemplo:
  • OutOfMemoryError => Erro que acontece quando os nossos programas tentam usar mais memória do que está disponível na máquina virtual
  • StackOverFlowError => acontece quando criamos um loop infinito.
A máquina virtual pode parar de executar por causa dos erros, um exemplo de como conseguir disparar um erro é mostrado a seguir:

//Exemplo de erro de loop infinitopublic boolean stackOverFlow(){   stackOverFlow();   return true;}//Exemplo de erro de estouro de memóriapublic void outOfMemory() {   List lista = new ArrayList();   while(true){      lista.add(new Professor());   }}

Exceções:

Exceções acontecem quando existe alguma coisa de errada no código, ou alguma parte do nosso sistema falha, como o acesso ao banco de dados ficou indisponível (servidor em manutenção), erro de conexão com algum serviço de rede, problemas com a interface de rede, etc.Quando estas falhas acontecem, o nosso sistema não pode parar, ele deve informar ao usuário que aconteceu um erro temporário, e este erro de ver tratado pelo nosso sistema, para mostrar uma mensagem que permita ao usuário entender o que está acontecendo.Toda vez que uma exceção é lançada pelo nosso código, a execução do método/construtor irá parar exatamente onde a exceção foi lançada.
Existem dois tipos de exceções as checáveis e as não checáveis. 


Exceções checáveis:

As exceções checáveis são aquelas onde nós temos que, obrigatoriamente tratá-las, quando um método/construtor as lança, estas exceções extendem Exception.

Exemplo de código com exceção checável:


public void conectaBanco(Connection conexao) throws IllegalArgumentException{
   if(conexao == null){
      throw new IllegalArgumentException("Conexao não pode ser nula");
   }
   //lógica omitida
}

No exemplo acima IllegalArgumentException é uma exceção checável, por isso obrigatoriamente temos que declarar ela na definição do método, usando a palavra throws. Com isso estamos dizendo que este método pode lançar uma exceção deste tipo.
Para acessar o método acima, temos que usar um try catch.

public void acessaConectaBanco() {   try{      conectaBanco(null);   } catch(IllegalArgumentException e) {      e.printStackTrace();   }}

Como IllegalArgumentException é uma exceção checável, obrigatoriamente temos que usar tratá-la no código que chama o método que a dispara e isso é feito através do try catch, que nada mais é do que uma expressão do tipo,
try{   ///tente executar este código}catch (IllegalArgumentException e){   //Caso aconteça uma exceção do tipo illegal argument exception, trate-a aqui.}

Voltando aos conceitos de orientação a objeto, o mesmo código poderia ter sido escrito assim:
public void acessaConectaBanco() {
   try{
      conectaBanco(null);
   } catch(Exception e) {
      e.printStackTrace();
   }
}

já que IllegalArgumentException extende Exception, que é a classe básica des exceções.

Exceções não checáveis:

As exeeções não checáveis, são as exceções que quando lançadas, não precisam ser declaradas no método/construtor, nem tratadas pelo código que executa o método/construtor, estas exceções extendem a classe RunTimeException.
Exceções não checadas:
public void conectaBancoRuntime(Connection conexao){
   if(conexao == null){
      throw new RuntimeException("Conexao nap pose set null");
   }
   //lógica omitida
}
Como estas exceções não precisam ser tratadas, nem declaradas, o mesmo código mostrado acima, poderia ter sido rescrito da seguinte maneira:

public void acessaConectaBancoRuntime() {
   conectaBancoRuntime(null);
}

Neste caso, quando chamarmos este método, a exceção será tratada pela classe que chamou o método acessaConexaoBancoRuntime.
Caso você queira tratar esta exceção lançada, você pode, usando um try catch, da seguinte forma:

public void acessaConectaBancoRuntime() {
   try{
      conectaBancoRuntime(null);
   } catch(RuntimeException e) {
      //tratamento de uma exceção
  }
}

PrintStackTrace:


A interface Throwable define um método chamado printStackTrace(); este método irá imprimir no console toda a lista de métodos que foi usada para chamar o método da exceção, no caso do método acessaConectaBanco, ele irá imprimir o seguinte:

Exception in thread "main" java.lang.IllegalArgumentException: Conexão não pode ser nula
at br.unip.erros.ExemploDeErros.conectaBanco(ExemploDeErros.java:39)
at br.unip.erros.ExemploDeErros.main(ExemploDeErros.java:48)
Acho podemos ver que a exceção aconteceu na thread main (thread principal do programa), foi uma exceção do tipo IllegalArgumentException. Aqui vemos também que a exceção foi lançada no método conectaBanco da classe ExemploDeErros na linha 39.

Exceções quando usar?

Visto os conceitos de exceções, ficamos tentados a extender a classe exception e criar um erro para cada atitude errada dos nossos usuários, ou para cada caso em que um método não retorne algo esperado, por exemplo, em uma tela de login, quando o usuário digita a senha errada, é muito mais fácil criarmos uma exceção SenhaInvalidaException e dispará-la, para depois tratarmos.
Na verdade, muitos dos exemplos encontrados na internet sobre exceções, incentivam este comportamento. A dica para usar é a seguinte:
Quando o seu cliente pode tomar alguma atitude que contornará a exceção, use exceção checada, já se o cliente não poderá fazer nada para contornar a exceção, use uma exceção não checada.
Dentre as principais desvantagens das exceções que podemos citar são:

  • Elas aumentam a quantidade de código escrita
  • Torna o código mais difícil de ler
  • Fragilizam a assinatura dos métodos
  • Não funcionam bem com interfaces
  • São pesadas demais
Carregar a stacktrace para mostrar no método printstacktrace não é uma operação nada fácil, isso requer várias operações na máquina virtual que são muito custosas, portanto a dica é evitar ao máximo.
Exceções devem ser usadas somente quando algo de extraordinário acontece, quando o resultado do método é algo esperado (é esperado que o usuário digite a senha errada, portanto o retorno deve ser algo que indique isso, e não uma exceção). Quando o comportamento do método for realmente algo que não de para tratar, ai sim devemos criar e disparar uma exceção.

Exercícios:

1) Determinar quais das exceções abaixo são do tipo checked, ou unchecked:
java.lang.NullPointerException
java.io.IOException
java.lang.NumberFormatException
java.lang.IllegalArgumentException

2) Altere a classe professor e faça com que ela dispare uma IllegalArgumentException quando ela receba um nome nulo ou vazio, um sobrenome nulo ou vazio.

3) Altere a classe matéria e faça com que ela dispare uma exceção IllegalArgumentException quando ela receba um Curso nulo.

Nenhum comentário:

Postar um comentário