26 março 2009

SCJP - 05 - Exceções e Assertivas

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:
  • Não use assertivas para validar parâmetros de métodos publicos. Como métodos públicos são a sua interface para o "mundo externo", você precisa garantir qualquer restrições quanto aos argumentos por si só.

  • Você pode usar assertivas para validar parâmetros de métodos privados. Isso parte da premissa que você pode controlar os pontos dos quais este método pode ser chamado, e a partir daí, fazer suposições coerentes.

  • Nunca use assertivas para validar parâmetros de linha de comando. Se realmente precisar validá-los, use exceções ao invés disso. Você pode pensar como se fosse algo semelhante ao primeiro item.

  • Nunca use expressões que possuam efeitos colaterais. Isso pode se referir a atribuições booleanas, métodos que retornem um booleano, coisas semelhantes.

  • Use assertivas, mesmo que em métodos públicos, para checar por código que nunca será alcançado. Note que isso é diferente do primeiro item. Um exemplo bastante simples é:

    switch(breguessu){
        case 2:
        case 4:
        case 6:
        case 8:
        case 0: break;
        default: assert(false); //assumindo que nunca 
                                 //vai passar aqui
    }
    


Comentários
0 Comentários

0 comments:

Postar um comentário

Regras são chatas, mas...

- Seu comentário precisa ter relação com o assunto do post;
- Em hipótese alguma faça propaganda de outros blogs ou sites;
- Não inclua links desnecessários no conteúdo do seu comentário;
- Se quiser deixar sua URL, comente usando a opção OpenID;
- CAIXA ALTA, miguxês ou erros de ortografia não serão tolerados;
- Ofensas pessoais, ameaças e xingamentos não são permitidos;