Submarino.com.br




Trabalhando com números em Java

Instanciando objetos de valor

Todos os objetos que herdam de Number contam com construtores para a instanciação. Contudo isto é um legado da versão 1.4 e anteriores do java que não deve ser usado na prática. Para instanciar um objeto de valor deve se usado o método valueOf(). Este método é,normalmente, sobrecarregado para aceitar argumentos primitivos e String. Para os objetos de valor que representam valores inteiros ( Byte, Short, Integer , BigInteger e Long) o uso de valueOf() é bastante simples, descomplicado e direto. Contudo, para os tipos decimais (Double, Float e BigDecimal) o uso de valueOf() pode ser bastante enganador. A regra a seguir para os tipos decimais é sempre deve ser preferido o uso do método valueOf() que recebe um objeto String. Desta forma não há perda de precisão, mesmo quando usamos Double e Float.

 
			
			// incorreto
			BigDecimal big = BigDecimal.valueof(1.23456);
			
			// correto
			BigDecimal big = BigDecimal.valueof("1.23456");
			
			
Código 1:

Apenas use as outras sobrecargas de valueOf() quando não conseguir ter acesso a uma representação em String.

Poderíamos esperar que os construtores destes objetos fossem mais amigáveis e cuidassem dos casos estranhos, conforme a própria documentação javadoc refere, esse não é o caso. O que significa que a atenção deve ser redobrada ao trabalhar com números decimais.

Convertendo entre objetos de valor

A conversão entre primitivos é feita através da operação de cast, contudo para objetos isso não é possível. Para converter entre os diferentes objetos de valor devemos recorrer à conversão para primitivos e o uso de valueOf(). Esta regra é válida para os valores inteiros, mas como sempre não se aplica para os tipos decimais.

Poderíamos pensar, por exemplo, que o código a seguir é uma forma legitima de converter um objeto Double para BigDecimal.

 
			
			// diretamente do valor primitivo
			
			BigDecimal big = BigDecimal.valueof(1.23456);
			
			// diretamente do wrapper
			Double d = Double.valueof(1.23456);
			
			BigDecimal big = BigDecimal.valueof(d.doubleValue());
			
			
Código 2:
Contudo, a forma seguinte - conforme explicado no Javadoc de BigDecimal, é preferível.
 
			
			
			// diretamente do valor primitivo
			
			BigDecimal big = BigDecimal.valueof(Double.toString(1.23456));
			
			// diretamente do wrapper
			Double d = Double.valueof(1.23456);
			
			BigDecimal big = BigDecimal.valueof(d.toString());
			
			
Código 3:
Esta conversão só funciona para os valores de double e float que BigDecimal aceita. Para valores como NaN(Not a Number) e infinity não há conversão possível

Comparações

Para os tipos primitivos o java ainda suporta os operadores de comparação == ( igual), > (maior), < (menor) , >= (maior ou igual) , <= (menor ou igual) e != (diferente).

Para tipos inteiros funciona perfeitamente, mas para double e float não é suficiente. Para uma explicação detalhada do porquê leia Comparando Objetos em Java, mas essencialmente os operadores normais não funcionam corretamente para comparar double e float e é necessário apelar para o método compare que se encontra no wrapper respectivo.

A moral da história é simples. Utilize apenas primitivos inteiros ( byte, short, char, int, long) para números inteiros e BigDecimal para decimais. Não use double nem float a menos que você saiba muito bem o que está fazendo. Utilizar estes tipos é o equivalente computacional de fazer malabarismos com motos-serras com as mãos empreganadas de óleo lubrificante. Só para especialistas... Para valores monetários utilize o padrão Money já que nenhum dos tipos primitivos, nem nenhuns dos objetos de valor asseguram as regras necessárias às operações aritméticas com dinheiro.