Classes

Classes de Número

Classes de número

Na linguagem Java, nos deparamos com tipos primitivos e valores literais mas também com objetos que representam números inteiros e fracionários. Os tipos numéricos que mais são utilizados nos milhares de projetos construídos são:

Explore cada uma delas e tenha em mãos um conjunto de recursos para trabalhar com números na linguagem.

Classes de Número

java.lang.Integer

A classe Integer representa números inteiros que vão de -2147483648 a 2147483647 e que oferece os recursos conforme abaixo:

Integer.MIN_VALUE //retorna o menor número suportado
Integer.MIN_VALUE //retorna o maior número suportado
Integer.valueOf("123"); //Converte um número em forma de texto (string) para número
Integer.toString(123); // Converte um número para texto (string)

Comparando números inteiros

Pode parecer simples até mesmo óbvio nesta etapa que estudos que comparar números utiliza-se o operador de ==, é até possível, mas muito cuidado com esta afirmação.

public class NumberApp {
    public static void main(String[] args) {

        Integer numero1 = 100;
        Integer numero2 = 100;

        System.out.println(numero1==numero2);
        System.out.println(numero1.equals(numero2));

        numero1 = 128;
        numero2 = 128;

        // acima de 127, internamente o Java cria um novo objeto do tipo Integer -> Integer numero1/2 = new Integer(128)
        // logo estamos agora nos referindo a dois objetos na aplicação.
        System.out.println(numero1==numero2);
        System.out.println(numero1.equals(numero2));
        System.out.println(numero1.intValue()==numero2.intValue());

    }
}

java.lang.Long

A classe Long representa números inteiros de uma escala elevada de valores que vão de -9223372036854775808 a 9223372036854775807 oferecendo recursos semelhantes à classe Integer.

Hoje devido não termos mais limitações de espaço e processamento em nossos computadores em relação à 20 anos atrás, usar Long para atribuir a tipos inteiros tem sido um hábito recorrente. Já pensou seu sistema possuir mais 2.147.483.647 clientes?

Cenários comuns para se utilizar Long:

public class NumberApp {
    public static void main(String[] args) {
        
        //considerar NÃO existir probabilidade de zero à esquerda
        Long celular;
        Long codigoBarras;

        /*
           Literais numéricos por padrão são convertidos para Integer
           Logo, é necessário acrescentar o sufixo L para determina-lo com Long     
         */
        Long numero = 130L;
    }
}

java.lang.Double

A classe Double representa números decimais em grande escala, onde a mesma é mais indicada do que a classe Float.

O que devemos considerar de agora em diante é que valores decimais, seguem a convenção americana conforme ilustrações abaixo:

public class NumberApp {
    public static void main(String[] args) {
        
        Double numeroDecimal =1234.5678;
        //representação BR -> 1.234,5678
    }
}
Existe uma enorme diferença entre o valor atribuído à uma variável, versus o valor exibido após uma formatação. Veja formatação de números decimais com NumberFormat e DecimalFormat.

Não é comum, mas é possível obtermos somente o valor inteiro de um Double através do método intValue();

public class NumberApp {
    public static void main(String[] args) {
        
        Double numeroDecimal =1234.5678;
        
        Integer numeroInteiro = numeroDecimal.intValue();
    }
}

java.math.BigDecimal

A classe BigDecimal vem com uma proposta de nos auxiliar na realização de operações matemáticas garantido resultados consistentes diante de inúmeros e complexos cálculos.

Formas de criar objetos tipo BigDecimal

public class NumberApp {
    public static void main(String[] args) {
     //Constantes
     BigDecimal zero = BigDecimal.ZERO;
     BigDecimal dez = BigDecimal.TEN;

     BigDecimal decimal = BigDecimal.valueOf(1234.5678);
     BigDecimal numeroString = new BigDecimal("1234.5678");
    }
}

Todas as operações matemáticas utilizando BigDecimal, necessitam de argumentos do tipo BigDecimal e retornam um novo BigDecimal imutável.

public class NumberApp {
    public static void main(String[] args) {
        
       BigDecimal um = BigDecimal.ONE;
       BigDecimal dez = BigDecimal.TEN;

       BigDecimal resultado = dez.add(um); // 11

       BigDecimal calculoComplexo = dez.subtract(um).divide(new BigDecimal(3));

       System.out.println(calculoComplexo); // ???

        /*
        add -> somar
        subtract -> subtrair
        multiply -> multiplicar
        divide -> dividir
        */

    }
}

Scala

Uma das principais vantagens em se utilizar BigDecimal é no aspecto de conseguirmos definir uma escala diante das nossas operações, exemplo:


public class NumberApp {
    public static void main(String[] args) {
        BigDecimal resultado = BigDecimal.TEN.divide(BigDecimal.valueOf(3));
        // Exceção:  Non-terminating decimal expansion; no exact representable decimal result.
    }
}
Matematicamente dividir 10 por 3 gera uma dízima periódica ou mais conhecido como número infinito
public class NumberApp {
  public static void main(String[] args) {
     BigDecimal divisor = BigDecimal.valueOf(3);
     BigDecimal resultado = BigDecimal.TEN.divide(divisor,3, RoundingMode.HALF_EVEN);
     System.out.println(resultado); //3.333
  }
}

Arrendodamento

Na matemática e muito menos na programação nem tudo são flores, veja a imagem ilustrativa abaixo:

Arrendamento

Temos a necessidade em exibir a multiplicação entre o valor preço por litro vezes a quantidade de litros apresentada.

public class NumberApp {
   public static void main(String[] args) {
      BigDecimal precoLitro = BigDecimal.valueOf(5.799);
      BigDecimal listrosUtilizados = BigDecimal.valueOf(21.752);
      BigDecimal valorPagar = listrosUtilizados.multiply(precoLitro);
      System.out.println(valorPagar); //126.139848
    
      //arredondando ...
      BigDecimal valorPagarArredondado = valorPagar.setScale(2, RoundingMode.HALF_EVEN);
      System.out.println(valorPagarArredondado); //126.14
   }
}
Mais um vez, não confunda arredondamento com formatação, arrendondar altera o valor real da variável enquanto que formatar gerar uma representação (string) do valor real.

Modos de arredondamento

Podemos sentir a necessidade de especificar alguns modos de arredondamento e para isso o Java provê a classe java.math.RoundingMode contendo opções pré-definidas (enum) de arredondamento, veja o exemplo abaixo:

public class NumberApp {
    public static void main(String[] args) {
        BigDecimal numero = BigDecimal.valueOf(1.5456);
   
        for(RoundingMode mode: RoundingMode.values()){
            if(mode == RoundingMode.UNNECESSARY)
                continue;
         
            System.out.println("Mode:" + mode.name() + " = "  +  numero.setScale(2, mode));
        }
       /*
        Mode:UP = 1.55
        Mode:DOWN = 1.54
        Mode:CEILING = 1.55
        Mode:FLOOR = 1.54
        Mode:HALF_UP = 1.55
        Mode:HALF_DOWN = 1.55
        Mode:HALF_EVEN = 1.55 **
        */
    }
}
ℹ️ Abaixo temos um exemplo prático quanto ao uso de BigDecimal

Depurando cálculos monetários

java.text.NumberFormat

A classe NumberFormat oferece recursos para conversão de números inteiros e decimais com base uma java.util.Locale (localização) informada retornando o número formatado em uma representação String.

Para criar uma instãncia de NumberFormat é necessário executar alguns de seus métodos de inicialização.

  • NumberFormat.getIntegerInstance() -> Retorna um formatador de números inteiros
  • NumberFormat.getNumberInstance() -> Retorna um formatador de números decimais sem o símbolo monetário
  • NumberFormat.getCurrencyInstance() -> Retorna um formatador de números decimais com o símbolo monetário
  • NumberFormat.getPercentInstance() -> Retorna um formatador de números decimais para representar a porcentagem de um valor entre 0.0 a 1.0
public class NumberApp {
    public static void main(String[] args) {
        //Testando em uma JVM com Locale pt-BR
        Integer inteiro = 12345678;
        NumberFormat formatador = NumberFormat.getIntegerInstance();
        String inteiroFormatado = formatador.format(inteiro);
        System.out.println(inteiroFormatado); // 12.345.678

        Double decimal = 123456.78;
        formatador = NumberFormat.getNumberInstance();
        System.out.println(formatador.format(decimal));// 123.456,78

        formatador = NumberFormat.getCurrencyInstance();
        System.out.println(formatador.format(decimal));// R$ 123.456,78

        Double porcentagem = 0.5;
        System.out.println(NumberFormat.getPercentInstance().format(porcentagem)); // 50%
    }
}
Quando necessitamos formatar valores numéricos inteiros ou decimais, devemos sempre considerar o idioma (localização) mencionando uma instância de java.util.Locale
public class NumberApp {
    public static void main(String[] args) {

        Double decimal = 123456.78;

        Locale ptBr = new Locale("pt","BR");
        NumberFormat formatadorBrasileiro = NumberFormat.getCurrencyInstance(ptBr);
        System.out.println(formatadorBrasileiro.format(decimal)); //R$ 123.456,78

        NumberFormat formatadorFrances = NumberFormat.getCurrencyInstance(Locale.FRANCE);
        System.out.println(formatadorFrances.format(decimal)); //123 456,78 €

        NumberFormat formatadorAmericano = NumberFormat.getCurrencyInstance(new Locale("en", "US"));
        System.out.println(formatadorAmericano.format(decimal)); //$123,456.78

    }
}

java.text.DecimalFormat

A classe DecimalFormat permite que você controle o formato dos números a serem apresentados após a formatação incluindo símbolo monetário, zeros à esquerda, agrupamentos decimais e etc.

Entendemos que a classe DecimalFormat permite formatar valores em diferentes padrões, dessa forma existe uma maior liberdade.

Veja a tabela abaixo:

SímboloDescrição
0Um dígito
#um dígito, zero mostra como ausente
.espaço reservado para separador decimal
,espaço reservado para seperador de grupo
¤Símbolo monetário

Agora vamos para alguns exemplos conforme tabela abaixo:

public class NumberApp {
    public static void main(String[] args) {
        String formato = "00000"; // 5 dígitos
        DecimalFormat formatador = new DecimalFormat(formato);

        for(int x=10; x<= 1000; x = x * 10) { // controle de fluxo mega power emmm ??
            System.out.println(formatador.format(x));
        }
        /* Resultado no console respectivamente
            00010
            00100
            01000
        */
    }
}
Concluímos que: Quando sua aplicação precisar realizar formatações com base na localização (idioma) é recomendado usar NumberFormat, caso não seja necessário, e sim, uma formatação única ou customizada, usa-se DecimalFormat.

java.util.Random

Os números aleatórios são utilizados de diversas formas em programas de computador, eles são importantes no desenvolvimento de simulação de jogos, ou informações que necessitam de uma aleatoriedade diante dos probibalidades dos possíveis valores apresentados.

As instâncias da classe Random são objetos geradores de números aleatórios, que produzem estes números em resposta a solicitações, veja exemplo abaixo:

public class Aleatorio {
    public static void main(String[] args) {
        Random random = new Random();
        System.out.println("Imprimindo números aleatórios");

        int numeroAleatorio = random.nextInt();
        
        System.out.println(numeroAleatorio);

        System.out.println(random.nextInt());

    }
}

Definindo um limite máximo

     //instância um objeto da classe Random usando o construtor básico
    Random gerador = new Random();

    //imprime sequência de 5 números inteiros aleatórios entre 0 e 9
    for (int i = 0; i < 5; i++) {
        System.out.println(gerador.nextInt(10)); // máximo até 9
    }
O valor máximo informado como parâmetro é excluído dos possíveis valores aleatórios retornados.

Definindo um limite inicial e final (excluído)

    //instância um objeto da classe Random usando o construtor básico
    Random gerador = new Random();

    //imprime sequência de 5 números inteiros aleatórios entre 5 e 10
    for (int i = 0; i <= 10; i++) {
        System.out.println(gerador.nextInt(11 - 5) + 5);
    }