Quando usar a classe primitiva vs em Java?

44

Eu vejo que Java tem booleano (classe) vs booleano (primitivo). Da mesma forma, há um Integer (class) vs int (primitivo). Qual é a melhor prática sobre quando usar a versão primitiva versus a classe? Deveria eu basicamente estar sempre usando a versão de classe a menos que eu tenha uma razão específica (performance?) Não? Qual é a maneira mais comum e aceita de usar cada um?

    
por Casey Patton 07.07.2013 / 10:15
fonte

5 respostas

40

No item 5, de Java efetivo, Joshua Bloch diz

The lesson is clear: prefer primitives to boxed primitives, and watch out for unintentional autoboxing.

Um bom uso para classes é ao usá-las como tipos genéricos (incluindo classes Collection, como listas e mapas) ou quando você deseja transformá-las em outro tipo sem conversão implícita (por exemplo, Integer class tem métodos doubleValue() ou byteValue() .

Edit: O motivo de Joshua Bloch é:

// Hideously slow program! Can you spot the object creation?
public static void main(String[] args) {
    Long sum = 0L;
    for (long i = 0; i < Integer.MAX_VALUE; i++) {
         sum += i;
    }
    System.out.println(sum);
}

This program gets the right answer, but it is much slower than it should be, due to a one-character typographical error. The variable sum is declared as a Long instead of a long, which means that the program constructs about 2^31 unnecessary Long instances (roughly one for each time the long i is added to the Long sum). Changing the declaration of sum from Long to long reduces the runtime from 43 seconds to 6.8 seconds on my machine.

    
por 07.07.2013 / 10:47
fonte
26

A prática padrão é usar as primitivas, a menos que você esteja lidando com genéricos (certifique-se de estar ciente de autoboxing e unboxing !).

Existem várias boas razões para seguir a convenção:

1. Você evita erros simples:

Existem alguns casos sutis, não intuitivos, que muitas vezes pegam iniciantes. Mesmo programadores experientes se enganam e cometem esses erros algumas vezes (esperamos que isso seja seguido de palavrões quando eles depurarem o código e encontrarem o erro!).

O erro mais comum é usar a == b em vez de a.equals(b) . As pessoas estão acostumadas a fazer a == b com primitivas, então é fácil de fazer quando você está usando os wrappers Object.

Integer a = new Integer(2);
Integer b = new Integer(2);
if (a == b) { // Should be a.equals(b)
    // This never gets executed.
}
Integer c = Integer.valueOf(2);
Integer d = Integer.valueOf(2);
if (c == d) { // Should be a.equals(b), but happens to work with these particular values!
    // This will get executed
}
Integer e = 1000;
Integer f = 1000;
if (e == f) { // Should be a.equals(b)
    // Whether this gets executed depends on which compiler you use!
}

2. Legibilidade:

Considere os dois exemplos a seguir. A maioria das pessoas diria que o segundo é mais legível.

Integer a = 2;
Integer b = 2;
if (!a.equals(b)) {
    // ...
}
int c = 2;
int d = 2;
if (c != d) {
    // ...
}

3. Desempenho:

O fato é que é mais lento para usar os wrappers do Object para primitivos do que apenas usar os primitivos. Você está adicionando o custo da instanciação de objetos, chamadas de método, etc. às coisas que você usa em todo o lugar .

Knuth's "... digamos 97% do tempo: a otimização prematura é a raiz de todo o mal", a citação não se aplica realmente aqui. Ele estava falando sobre otimizações que tornam o código (ou sistema) mais complicado - se você concorda com o ponto # 2, esta é uma otimização que torna o código menos complicado!

4. É a convenção:

Se você faz escolhas estilísticas diferentes para 99% dos outros programadores Java, existem duas desvantagens:

  • Você encontrará o código de outras pessoas mais difícil de ler. 99% dos exemplos / tutoriais / etc por aí usarão primitivos. Sempre que você lê um, você tem a sobrecarga cognitiva extra de pensar sobre como ele ficaria no estilo que você está acostumado.
  • Outras pessoas acharão seu código mais difícil de ler. Sempre que você fizer perguntas sobre o Stack Overflow, terá que filtrar as respostas / comentários perguntando "por que você não está usando primitivos?". Se você não acredita em mim, basta olhar para as batalhas que as pessoas têm sobre coisas como posicionamento de colchetes, o que nem afeta o código gerado!

Normalmente eu listaria alguns contra-pontos, mas sinceramente não consigo pensar em nenhuma boa razão para não aceitar a convenção aqui!

    
por 08.07.2013 / 16:31
fonte
12

Geralmente eu uso as primitivas. No entanto, uma peculiaridade do uso de classes como Integer e Boolean é a possibilidade de atribuir null a essas variáveis. Naturalmente, isso significa que você precisa fazer null checks o tempo todo, mas ainda é melhor obter um NullPointerException do que ter erros de lógica devido ao uso de uma variável int ou boolean que não foi inicializada corretamente. / p>

Além disso, introduz a possibilidade de usar null para atribuir a essas variáveis um valor " desconhecido " ou " curinga ". Isso pode ser útil em algumas situações, por exemplo, na Lógica Ternária . Ou você pode querer verificar se um determinado objeto corresponde a algum modelo; Nesse caso, você pode usar null para essas variáveis no modelo que podem ter qualquer valor no objeto.

    
por 07.07.2013 / 11:23
fonte
2

Nas palavras do leigo:

Você usa os wrappers quando precisa adicionar itens às coleções.

As coleções não podem conter primitivos.

    
por 08.07.2013 / 16:17
fonte
0

Recursos Java de autoboxing como m3th0dman apontou. Pense no nível mais baixo possível e você verá que o autoboxing (in ou out) de um valor primitivo implicará ciclos de clock gastos em algumas tarefas que você não precisa se estiver trabalhando com tipos de dados nativos em torno de seu aplicativo.

Como regra geral, você deve tentar usar tipos de dados nativos sempre que possível.

    
por 08.07.2013 / 16:20
fonte