Ir para o conteúdo

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.

(...)


  1. classes Integer, Boolean, Double, etc. 

  2. 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. 

  3. Em números positivos o sinal é omitido mas podemos quer mostrá-lo. 

  4. 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. 

  5. 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.