Trabalhando com o mecanismo de assertivas em Java

Veja neste artigo conceitos e dicas sobre a utilização de assertivas na linguagem de programação Java.

Todo desenvolvedor trabalha em cima de suposições de fluxo. Antigamente, os programadores utilizavam saídas ou comentários para ajudar a confirmá-las em tempo de execução. A partir da versão 1.4 da linguagem Java, vieram as assertivas. Com elas, eles não precisaram mais poluir seus códigos com saídas e/ou comentários de testes.

Assertivas

Durante o desenvolvimento de um sistema existem vários fluxos lógicos, nos quais os programadores precisam garantir que eles sejam seguidos, ou não. Para isto, é necessário algum tipo de feedback do próprio sistema a fim de se ter garantias do bom funcionamento do programa. Porém, é, de fato, cansativo ter que inserir linhas de instruções println, manipuladores de exceções ou testes if/else para executar esta função. Além disto, é mais custoso ainda retirá-las após a finalização do sistema para que elas não causem impacto no desempenho.

Por exemplo, antes da versão 1.4, se fosse necessário confirmar de que um número sempre terá o valor positivo, o seguinte código seria feito:

Listagem 1: Validação de número positivo

private void doCalc(int number) { if (number >= 0) { // Faz algo com o número }else { // O programa jamais deveria chegar aqui... System.out.println("Erro! O programa chegou a um ponto onde não deveria estar..."); } }

O código anterior, se não corrigido posteriormente, será entregue ao cliente do jeito que está, com comentários e condições de testes. Assumindo que existe uma certeza de que o número jamais seria negativo, é recomendado que se utilize assertiva já que seu código, quando a aplicação for distribuída, simplesmente desaparecerá. O compilador se encarregará de gerar a classe sem as declarações de asserts, pois elas já foram desenvolvidas com a finalidade de testes, apenas.

Atualizando a nossa validação anterior com asserts, teríamos:

Listagem 2: Validação de número positivo com assert

private void doCalc(int number) { assert(number>=0); // Só chegará aqui se a condição anterior for verdadeira. // Caso contrårio, lancará uma AssertionError em tempo de execução. System.out.println("Está tudo certo!"); }

O código anterior fará com que o programa lançe uma exceção em tempo de execução caso o número não seja positivo. Isto acontece porque, como mencionado anteriormente, temos a certeza de que a lógica estará errada caso o número seja negativo. Então, é correto lançar uma exceção para que o programador reveja sua lógica e conserte o que estiver errado.

Assertivas além de deixarem o código mais limpo, são, por default, desativadas. Ou seja, o código da Listagem 2, caso as assertivas sejam ativadas nos argumentos, será interpretado pelo compilador como o seguinte código:

Listagem 3: Código interpretado pelo compilador sem assertivas ativas

private void doCalc(int number) { // Só chegará aqui se a condição anterior for verdadeira. // Caso contrårio, lancará uma AssertionError em tempo de execução. System.out.println("Está tudo certo!"); }

Como podemos ver, a assertiva desapareceu! E, uma vez que queremos entregar a aplicação com seu melhor desempenho possível, é isso que queremos na versão final da aplicação! Porém, quando for preciso a utilização delas para os testes durante o desenvolvimento, será necessário habilitalas com o argumento de linha de comando -enableassertion ou -ea, ficando a linha de comando deste jeito:

Listagem 4: Habilitando assertivas através da linha de comando

java -ea Teste

Isto fará com que o compilador reconheça toda as assertivas no código. Serão lançadas AssertionError em todas aquelas assertivas nas quais suas condições forem falsas. Por exemplo, se enviarmos para o método “doCalc” um número negativo, é esperado que, com as assertivas ativas, seja lançado um AssertionError, como no cenário a seguir:


Figura 1: Aplicação com cenário de erro com as assertivas ativadas

Assim como, se enviarmos um número positivo, esperamos que nenhum exceção seja lançada e, no caso do exemplo, um instrução println seja chamada.


Figura 2: Cenário perfeito com assertivas ativadas

Observação: Jamais manipule a AssertionError, pois é através dela que o desenvolvedor saberá onde terá que corrigir o erro.

Tipos de assertivas

Existem dois tipos bastantes simples de se declarar uma assertiva:

Forma muito simples:

Listagem 5: Sintaxe muito simples de se declarar assertiva

assert(expressão);

Utilizamos este tipo de assertiva nos exemplos anteriores.

Forma simples:

Listagem 6: sintaxe simples de se declarar uma assertiva

assert (expressão): mensagem;

A única diferença entre as duas é a mensagem adicionada ao erro na forma simples. Esta mensagem ajudará na identificação e explicação do erro.

Regras das expressões de assertivas

A primeira expressão sempre deverá resultar em um valor booleano. Para facilitar, siga as mesmas regras de uma instrução if. A segunda expressão - utilizada apenas na sintaxe simples - deverá sempre ser algo que retorne algum valor no qual poderá ser convertido em string. Encare esta segunda expressão como algo similar ao println, pois todo valor será convertido para string e adicionado ao stack trace, fornecendo algumas informações de depuração.

Exemplos de expressões válidas e inválidas para ambos os casos:

Listagem 7: Exemplos de expressões válidas e inválidas das assertivas

void noreturn() {} int aReturn() {return i;} void go() { int x = 1; boolean b = true; // as seguintes instruções assert são válidas assert(x == 1); assert(b); assert(x == 1): x; assert(x == 1): aReturn(); assert(x == 1): new ValidAssert(); // as seguintes instruções assert são INVÁLIDAS assert(x = 1); // Nenhuma delas é booleana assert(x); assert 0; assert(x == 1): ; // A segunda não retorna um valor assert(x == 1): noReturn(); assert(x == 1): ValidAssert va; }

Usando as assertivas apropriadamente:

Não use assertivas para validar argumentos de um método public.

Métodos public poderão ser chamados de qualquer lugar. Ou seja, você não terá a garantia de que algum lugar desconhecido por você estará chamando este método com o argumento esperado. Para proteger sua aplicação, defina o método como private.

Não use assertivas para validar argumentos de linha de comando

Mesmo caso de métodos public. Você não terá controle sobre os argumentos que virão da linha de comando.

Não use assertivas que possam causar efeitos colaterais!

A regra é: uma assertiva deve deixar o programa no mesmo estado em que estava antes da expressão! Ora, se não temos a garantia de que a assertiva irá lançar uma exceção ou não, por que depender dela para executar alterações no sistema?!

Com isto, finalizo o artigo referente a utilização de assert em Java. Espero ter ajudado no entendimeto deste recurso tão útil aos desenvolvedores.

Abraço!

Referência:

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados