Olá Pessoal, tudo bem?
O artigo de hoje irá tratar sobre a contextualização e utilização de Exceptions.
Contextualizando Exceptions
A classe base para qualquer exceção no Java é a java.lang.Throwable, como diz o JavaDoc da classe:
The Throwable class is the superclass of all errors and exceptions in the Java language. Only objects that are instances of this class (or one of its subclasses) are thrown by the Java Virtual Machine or can be thrown by the Java throw statement. Similarly, only this class or one of its subclasses can be the argument type in a catch clause.
Desse JavaDoc podemos extrair várias informações. Primeiro a classe Throwable é a superclasse de todos os erros e exceções na linguagem Java. Assim apenas instancias dessa classe, ou filhas, podem serem “lançadas” pela JVM.
Segundo, se vc for utilizar um throw para “lançar” uma exceção ou try/catch para “pegar” essas exceções, somente instâncias de Throwable ou suas filhas podem satisfazer a necessidade dessas estruturas, pois senão haverá erros de compilação.
Assim devemos utilizar a classe java.lang.Throwable ou alguma filha para criarmos a nossa própria exception. O caso mais comum é utilizar a classe java.lang.RuntimeException, pois de acordo com o JavaDoc dessa classe:
RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java Virtual Machine.
RuntimeException and its subclasses are “unchecked exceptions”. Unchecked exceptions do not need to be declared in a method or constructor’s throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.
Assim desse segundo JavaDoc temos a informação que uma instância de RuntimeException, ou filha, pode ser lançada como uma operação normal pela JVM, pois elas são “Unchecked exceptions”, ou seja, não é necessário declarar no método que este lança determinada exception, pois isso é absorvido pela JVM. Isso é muito bom, pois não existe a necessidade de modicar assinaturas de métodos, ainda mais se estamos trabalhando com o conceito de serviços e módulos utilizados por outros sistemas, onde uma mudança em uma assinautura de um método pode comprometer outros projetos.
“Lançando” (Throw) uma exceção
Para lançar uma exception, é utilizado a palavra chave throw seguindo da instância da exception. Normalmente não temos a instância da exception que será lançada, então a exception é criada no momento do lançamento. O código abaixo, representado pelo método validateForDataModification() realiza essa operação:
1 2 3 4 5 |
public void validar() { if (this.endereco == null) { throw new RuntimeException("Endereco precisa estar preenchido!"); } } |
Explicando um pouco o código acima, existe uma validação anterior que verifica se um atributo interno da classe chamado “endereco” está nulo. Se caso esteja é lançada uma nova instância de RuntimeException com a mensagem “Endereco precisa estar preenchido“. Não existe nenhuma referencia à RuntimeException no método, pois é uma unchecked exception.
Caso, fosse lançado uma exception que não fosse unchecked, deveria ser adicionado a palavra chave throws na assinatura do método. Por exemplo, ao lançar a IOException, essa é uma checked exception, ou seja, existe uma forma de tratar essa exception é já existe um conhecimento de antemão que isso pode acontecer. Veja o código abaixo o que acontece:
1 2 3 4 5 6 7 |
import java.io.IOException; //Algumas linhas de código depois dentro de uma classe public void abrirArquivo(String enderecoArquivo) throws IOException { //Código que tenta abrir um arquivo, caso não encontre lança uma IOException } |
Note que foi necessário acionar a palavra chave throws seguido da Exception requerida, caso exista mais de uma checked exception, deverão ser adicionadas vírgulas para separar as exceções. Por exemplo:
1 2 3 4 5 6 7 |
import java.io.IOException; //Algumas linhas de código depois dentro de uma classe public void abrirArquivo(String enderecoArquivo) throws IOException, PathException { //Código que tenta abrir um arquivo, caso não encontre lança uma IOException ou PathException } |
“Pegando” (Catch) uma exceção
Quando lançamos uma exceção de alguma forma deve ser capturada pelo nosso código, pois dependendo do erro pode forçar o encerramento abrupto do programa. Assim a forma com que capturamos uma exception na linguagem Java é utilizando a clausula try catch. Veja o código abaixo, ele possui uma chamada ao método validar():
1 2 3 4 5 6 7 |
public void validarApresentandoErro(){ try{ this.validar(); } catch (RuntimeException e){ this.apresentarErro(e.getMessage()); } } |
A partir do Java 8 é possível aninhar mais de uma exception dentro da clausula catch, por exemplo ao chamar o método abrirArquivo:
1 2 3 4 5 6 7 |
public void abrirArquivoApresentandoErro(String enderecoArquivo){ try{ this.abrirArquivo(enderecoArquivo); } catch (IOException | PathException e){ this.apresentarErro(e.getMessage()); } } |
Por fim a clausula try catch ainda possui uma outra parte chamada finally, utilizada para realizar atividades, mesmo que uma exceção aconteça, por exemplo, fechar uma conexão com o banco de dados, independente se o registro for inserido com sucesso ou acontecer uma exceção a conexão deve ser fechada. Veja no exemplo abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public void insert(T obj) { Session session = HibernateUtil.getSession(); Transaction tx = null; try { tx = session.beginTransaction(); session.persist(obj); tx.commit(); } catch (Exception ex) { if (tx != null) { tx.rollback(); } throw new SeminariosCientificosException(ex); } finally { session.close(); } } |
finally {
Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Leave a Reply