Formatação e Conversão de Números
Quando se desenvolvem aplicações, seja em Java ou noutra linguagem, é comum que se lide com números que estão guardados em variáveis de texto, tipicamente porque esses números provêm de algum local externo à nossa aplicação. A conversão desse texto para o seu valor numérico é acaba por ser algo bastante comum.
Quando pretendemos mostrar números ao utilizador é importante que os mesmos sejam formatados para um aspecto que seja o esperado pelo utilizador, por exemplo, em Portugal usamos o ponto como separador dos milhares, outros países usam a vírgula.
Como podemos ver, conversões e formatações de números são operações bastante comuns no desenvolvimento de aplicações. Em Java essas tarefas são bastante simples de executar e iremos verificar isso nos parágrafos seguintes.
Strings para Valores Numéricos
Todas as classes encapsuladoras de tipos primitivos1, possuem, pelo menos, dois métodos de conversão de Strings, o método valueOf(), permite converter a String passada para um objecto encapsulador, o método parseXXX permite converter para o tipo primitivo2.
String s = "10.5";
Integer i = Integer.valueOf(s); //criar objecto encapsulador com o valor 10.
int i2 = Integer.parseInt(s); //obter o valor primitivo, 10.
Double d = Double.valueOf(s);
double d2 = Double.parseDouble(s); //obter o valor primitivo, 10.5
Converter é simples, mas é necessário ter em atenção alguns aspectos:
- a conversão é feita segundo as definições regionais do sistema operativo.
- se a conversão falhar é lançada uma excepção de runtime que nos permite recuperar ou tratar situações de erro. Importante quando estamos a pedir valores directamente ao utilizador sem que os possamos validar primeiro.
- os métodos parseXXX assumem, por omissão, que estamos a trabalhar com números em base 10.
try {
System.out.println("Introduza um número");
//ler input do utilizador, assumimos que o input é retomado para uma variável do tipo String chamada "in"
Interger i = Integer.valueOf(in);
int i2 = Integer.parseInt(in);
Float f = Float.valueOf(in);
float f2 = Float.parseFloat(in);
Double d = Double.valueOf(in);
Double d2 = Double.parseDouble(in);
} catch (NumberFormatException ex) {
System.out.println("O valor introduzido não é um número");
}
Formatação de Números
Neste caso estamos a tentar alterar a forma de apresentação de valores que já possuímos, mas que pretendemos mostrar ao utilizador. Esta A formatação recorre às classes NumberFormat e DecimalFormat ou dos métodos format() da classe PrintStream.
A classe NumberFormat é uma classe de formatação genérica, permite alterar a apresentação dos valores através do uso de máscaras, essas máscaras, compostas por um conjunto de caracteres pré-definidos, permitem especificar de que forma os nossos valores vão ser tratados, indicando o número de casas decimais, presença ou omissão do sinal3, etc.
Esta classe é abstracta e usa o padrão de desenho Factory para a criação das instâncias. Obter uma instância de NumberFormat implica que a JVM terá de ler um conjunto relativamente grande de opções, todas elas provenientes do nosso sistema operativo, e criar uma instância que funcione em conformidade com essas opções, se vamos formatar vários números, é vantajoso obter a instância apenas uma vez e guardar uma referência para ela.
NumberFormat nf = NumberFormat.getInstance(); //obter uma instância de NumberFormat,
//com todas as definições regionais
//do nosso Sistema operativo
nf.format(123.45); //formatar um número
Podemos querer formatar os nossos números seguindo definições regionais diferentes das introduzidas no sistema operativo4, para tal basta indicarmos qual a região que pretendemos usar.
NumberFormat nf = NumberFormat.getInstance(Locale.CHINESE); //obter uma instância de NumberFormat,
//especificando a região usada
nf.format(123.45);
Além da classe NumberFormat, podemos usar para números decimais5, a classe DecimalFormat. Esta não é, ao contrário da sua superclasse, uma classe abstracta.
(...)
-
classes Integer, Boolean, Double, etc. ↩
-
Na verdade, o primeiro método recorre ao segundo para criar o objecto, podemos ver isso na implementação da classe Integer onde o método valueOf é construído através de: Integer(parseInt(s, 10));, onde "s" é a string passada. ↩
-
Em números positivos o sinal é omitido mas podemos quer mostrá-lo. ↩
-
Garantimos assim que, se necessário, a região usada não fica dependente do utilizador ter configurado correctamente o seu sistema operativo. Atenção que esta situação deverá ser seguida apenas em casos onde seja realmente justificável, de outro forma arriscamos a que a nossa aplicação não funcione como o utilizador espera. ↩
-
Na verdade, podemos usar também para inteiros, já que estes serão um caso especial dos números decimais, podem ser vistos como um número decimal onde a componente após a vírgula é sempre zero. ↩