DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Item 61: Dê preferência aos tipos primitivos em vez dos tipos primitivos empacotados

Tipos Primitivos vs. Tipos Primitivos Empacotados

  • Tipos Primitivos: int, double, boolean, etc.
  • Tipos Primitivos Empacotados: Integer, Double, Boolean, etc.
  • O Java possui um sistema de tipos duplo: tipos primitivos e tipos de referência (objetos).
  • Cada tipo primitivo tem um correspondente empacotado (wrapper class).

Diferenças Principais

  • Identidade vs. Valor:
    Primitivos: Não possuem identidade; dois primitivos com o mesmo valor são sempre iguais.
    Empacotados: São objetos e possuem identidade; dois objetos podem ter o mesmo valor, mas identidades diferentes.

  • Valores Nulos:
    Primitivos: Sempre têm um valor padrão (por exemplo, 0 para int).
    Empacotados: Podem ser null, o que pode levar a exceções NullPointerException se não tratados adequadamente.

  • Desempenho:
    Primitivos: Mais eficientes em termos de tempo e espaço.
    Empacotados: Introduzem overhead devido à criação de objetos adicionais.

Problemas Comuns ao Misturar Primitivos e Empacotados

  • 1. Comparação de Identidade em Vez de Valor
  • Ao comparar objetos empacotados usando ==, você está comparando referências de objeto, não os valores. Isso pode levar a resultados inesperados.

Exemplo Problemático:

Comparator<Integer> naturalOrder = (i, j) -> (i < j) ? -1 : (i == j ? 0 : 1);

Enter fullscreen mode Exit fullscreen mode

Problema: A comparação i == j compara referências, não valores.
Comportamento Incorreto: naturalOrder.compare(new Integer(42), new Integer(42)) retorna 1 em vez de 0.

Solução:
Use o método compareTo ou métodos utilitários da classe Integer.

Comparator<Integer> naturalOrder = Integer::compare;

Enter fullscreen mode Exit fullscreen mode

Ou, corrigindo o comparador original:

Comparator<Integer> naturalOrder = (iBoxed, jBoxed) -> {
    int i = iBoxed;
    int j = jBoxed;
    return (i < j) ? -1 : ((i == j) ? 0 : 1);
};

Enter fullscreen mode Exit fullscreen mode

2. Autounboxing e NullPointerException
Ao usar tipos empacotados que podem ser null, o autounboxing pode lançar exceções se o objeto for null.

Exemplo Problemático:

Integer i = null;
if (i == 42) {
    System.out.println("Inacreditável");
}

Enter fullscreen mode Exit fullscreen mode

Problema: i é null; ao comparar com 42, ocorre autounboxing de null, resultando em NullPointerException.
Solução: Use tipos primitivos quando possível.

int i = 0;
if (i == 42) {
    System.out.println("Inacreditável");
}

Enter fullscreen mode Exit fullscreen mode

3. Desempenho Degradado devido ao Autoboxing/Unboxing
O uso inadvertido de tipos empacotados em operações intensivas pode causar degradação de desempenho devido ao autoboxing e criação desnecessária de objetos.

Exemplo Problemático:

Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
    sum += i;
}
System.out.println(sum);

Enter fullscreen mode Exit fullscreen mode

Problema: sum é um Long empacotado; em cada iteração, ocorre autoboxing/desempacotamento.

Impacto: Código muito mais lento e uso excessivo de memória.
Solução:
Use tipos primitivos para variáveis locais em operações intensivas.

long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
    sum += i;
}
System.out.println(sum);

Enter fullscreen mode Exit fullscreen mode

Quando Usar Tipos Empacotados

  • Coleções: Não é possível usar tipos primitivos em coleções genéricas (por exemplo, List).
  • Parâmetros Genéricos: Tipos genéricos não suportam tipos primitivos (por exemplo, ThreadLocal).
  • APIs que Requerem Objetos: Certas APIs exigem objetos em vez de tipos primitivos.

Boas Práticas

  • Prefira Tipos Primitivos: Sempre que possível, use tipos primitivos para simplicidade e eficiência.
  • Cuidado com o Autoboxing/Unboxing: O autoboxing reduz a verbosidade, mas pode introduzir erros sutis.
  • Evite Comparações com == em Empacotados: Use métodos como equals() ou compare os valores desempacotados.
  • Verifique Nulos: Ao trabalhar com tipos empacotados, esteja ciente de que podem ser null e causem NullPointerException.

Resumo
Tipos Primitivos:
Mais simples e rápidos.
Não podem ser null.
Não têm identidade (apenas valor).

Tipos Empacotados:
Necessários para uso em coleções e APIs genéricas.
Podem ser null.
Têm identidade de objeto.

Top comments (0)