Ando meio sem estímulo pra continuar lendo, mas como terminei o capítulo 5 faz alguns dias, estou devendo os posts/resumos pra mim mesmo :) Sendo assim, a gente continua, pontuando coisas não muito vistas e/ou importantes no que se refere a manipulação de exceções.
Nós, como bons garotos de programa, já sabemos que exceções interrompem o fluxo normal de um programa. Sabemos que é possível envolver o código passível de exceções com um bloco try/catch, ou simplesmente deixar que o método chamador cuide da exceção por nós.
try {
//codigo que gera exceção
} catch (SomeException1 ex) {
//codigo que trata exceção
} catch (SomeException2 ex) {
//codigo que trata exceção
}
public void metodo() throws SomeException{
//codigo que gera exceção
}
O primeiro ponto importante a ser lembrado é que o código que trata a exceção (o catch) é analisado na ordem em que ele é declarado, ou seja, de cima para baixo. Imagine que uma exceção A seja superclasse de uma exceção B, e que as duas estejam sendo tratadas num bloco try/catch.
try {
//alguma coisa
} catch (A a) {
//outra coisa
} catch (B b) {
//qualquer coisa
}
Se A tiver sido posicionada antes de B, ocorre um erro de compilação, cuja mensagem informa que o código que trata a exceção B nunca será alcançado. Porque? Widening... Todas as vezes que a exceção B for lançada, será tratada pelo código mais geral, ou seja, aquele que trata A, justamente porque a análise feita para encontrar um manipulador de exceções adequado é top-down.
Outra coisa curiosa é o bloco do finally. Ele é executado se a exceção for capturada ou não. Ele é executado mesmo se dentro do catch houver um return. Querem testar?
class TesteException extends Exception{}
public class Principal {
public void teste(boolean excecao) {
try {
if (excecao) {
throw new TesteException();
}
} catch (TesteException tex) {
System.out.println("retornando...?");
return;
} finally {
System.out.println("um momento por favor");
}
}
public static void main(String[] args) {
Principal p = new Principal();
p.teste(false);
System.out.println("agora sim");
p.teste(true);
System.out.println("agora sim");
}
}
Lembre-se que nem o catch, nem o finally são obrigatórios, mas não deve haver um bloco try sem um catch ou um finally. Se não houver um try, e o código for passível de exceções verificadas (aquelas que não herdam de RuntimeException), tais exceções devem ser declaradas na interface publica do método, atravéz da palavra chave throws.
Não são só as exceções que alteram o fluxo de execução. Você pode fazer certas suposições, e caso elas sejam falsas, lançar algo semelhante a uma exceção, parando o fluxo de execução do programa. Isso é possível com assertivas :)
void metodo() {
//algum código util (ou nao)
assert(x >= 0);
//código que assume que x seja positivo
}
Caso x seja negativo, um AssertionError (subclasse de Error) é lançado. Note que, assim como nos if, while, do, e for, a única coisa que vai entre os parêntesis do assert() é uma condicional. Qualquer coisa diferente disso gera erro de compilação. No máximo, é possivel colocar uma mensagem de erro que possa ser exibida junto com o estado atual da pilha de chamadas:
//exibindo uma string, ou qualquer coisa que
//possa ser convertida para uma string
assert(x >= 0) : "x é negativo: " + x;
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. [Javadoc 1.6]
As assertivas só funcionam se você habilitá-las em tempo de execução, através de parâmetros passados à JVM.
java -ea pacote.Classe
ou
java -enableassertions pacote.Classe
Apesar das assertivas serem desabilitadas por padrão, é possível desabilitadas através de comandos como
java -da pacote.Classe
ou
java -disableassertions pacote.Classe
E a partir daí, é possível habilitar as assertivas em somente uma classe específica
java -ea:pacote.qualquer.Classe pacote.Principal
Ou em um determinado pacote (e subpacotes)
java -ea:pacote.subpacote... pacote.Principal
Ou quem sabe ainda habilitá-las no geral, e desabilitalas apenas para um determinado pacote
java -ea -da:pacote.subpacote... pacote.Principal
Só fique atento para as seguintes regras: