Quando criamos classes em
Java, um dos pontos mais importantes é proteger o estado dos objetos
que serão ou estão instanciados. Uma das maneiras de se atingir este objetivo
é colocar infindáveis estruturas “if/throw” para testar os
parâmetros de construtores e métodos, dificultando a legibilidade
de nosso código. Como no construtor abaixo:
public
Livro(String titulo, int
paginas) throws
IllegalArgumentException {
if
(titulo == null)
throw
new
IllegalArgumentException("titulo
não pode ser nulo");
if
(titulo.length() < 0)
throw
new
IllegalArgumentException("O
tamanho de titulo deve ser maior que zero");
if
(paginas < 0)
throw
new
IllegalArgumentException("paginas
deve ser maior que zero");
this.titulo
= titulo;
this.paginas
= paginas;
}
Estas estruturas ficam
espalhadas por todo nosso código. Podemos até criar métodos específicos
que façam estes testes, mas então o tamanho das classes aumentam
cada vez mais.
Para facilitar nosso
trabalho e manter o código limpo, podemos utilizar a biblioteca
Guava. Para quem não conhece,
Guava é um biblioteca que fornece
várias classes utilitárias e é desenvolvida pelo
Google. Guava
segue vários conceitos do livro “
Effective Java” de
Joshua Bloch,
que aliás trabalhou na arquitetura do projeto. Além disso, o Google
utiliza a biblioteca em seus próprios projetos Java, que com certeza
traz confiança na qualidade da mesma.
Na biblioteca encontramos
a classe
Preconditions, que pode facilitar os testes de argumentos e
estados de objetos, tornando nosso código mais limpo e bonito. A
classe Preconditions possui seis métodos, sendo que todos são estáticos.
Desta forma pode-se usar “import static” para facilitar o
trabalho. Os métodos e as exceções que estes lançam são:
Método
|
Exceção Lançada
|
checkArgument(boolean)
|
IllegalArgumentException
|
checkNotNull(T)
|
NullPointerException
|
checkState(boolean)
|
IllegalStateException
|
checkElementIndex(int
index, int size)
|
IndexOutOfBoundsException
|
checkPositionIndex(int
index, int size)
|
IndexOutOfBoundsException
|
checkPositionIndexes(int
start, int end, int size)
|
IndexOutOfBoundsException
|
Um método muito
interessante é o checkArgument(), que testa uma expressão booleana
e lança IllegalArgumentException caso esta for falsa.
checkArgument(paginas
> 0,"O
valor de paginas(%s) deve ser maior que zero",
paginas);
Neste caso foi utilizado
o método sobrecarregado que aceita como parâmetro uma String
formatável para mostrar uma mensagem.
Outro exemplo é o checkNull, que verifica se o
argumento passado é nulo. Podemos atribuir o valor do parâmetro ao
campo diretamente, pois o retorno do método é o próprio valor que
foi testado:
this.titulo
= checkNotNull(titulo,
“titulo
não pode ser nulo”);
Caso o parâmetro for
nulo, NullPointerException será lançada e a mensagem será exibida.
O método checkState
avalia se o estado do objeto é correto ao se chamar um determinado método. Você
pode imaginar uma classe Builder, com vários métodos “set”
para os campos que serão utilizados para construção de um objeto.
Ao charmar o método build(), alguns campos não podem ter
determinado valor ou null. Exemplo simplificado:
import
static
com.google.common.base.Preconditions.*;
public
class
ExemploBuilder {
private
int
tamanho;
private
String nome;
public
ExemploBuilder setTamanho(int
tamanho) {
this.tamanho
= tamanho;
return
this;
}
public
ExemploBuilder setNome(String nome) {
this.nome
= nome;
return
this;
}
public
Exemplo build() throws
IllegalStateException {
checkState(tamanho
> 0,
"deve-se
fornecer tamanho com valor maior que zero");
checkState(nome
!= null,
"nome
não pode ser nulo");
return
new
Exemplo(this.tamanho,
this.nome);
}
class
Exemplo {
private
int
tamanho;
private
String nome;
public
Exemplo(int
tamanho, String nome) {
this.tamanho
= tamanho;
this.nome
= nome;
}
}
public
static
void
main(String[] args) {
//lançará
uma exceção.
new
ExemploBuilder().setTamanho(5).build();
}
}
O checkState não avalia
os parâmetros do método em si, mas se o estado do objeto é seguro
ao se chamar o método. Outro exemple, seria um objeto resultSet, que é retornado após uma consulta em um banco de dados. Os
métodos “get” só podem ser chamados após o método
next() ser invocado.
O método checkElementIndex verifica se o valor de um índice é
válido para um array, string ou outra lista qualquer. Como
parâmetro, ele requer o valor do índice e o tamanho da lista. Veja
o exemplo:
int[]
a = {5,8,9,4,6};
checkElementIndex(4,
a.length);
Este foi um artigo demonstrando alguns métodos da classe Preconditions do Guava. O Guava possui muitas outras utilidades interressantes que podem ser consultadas na página do projeto ou também no
Wiki.
Este
artigo de Markus Sprunk fala de Preditons e outros métodos de verificação de argumentos em Java, fazendo uma comparação interessante.
Até mais.