Pergunta

Misturando o uso de tipos de dados primitivos e suas respectivas classes de mensagens publicitárias, em Java, pode levar a um monte de bugs. O exemplo a seguir ilustra a questão:

int i = 4;
...
if (i == 10)
  doStuff();

Mais tarde você descobrir que você deseja que a variável i para ser tanto definido ou indefinido, para que mudar a instanciação acima para:

Integer i = null;

Agora, a verificação de igualdade falha.

É uma boa prática Java para usar sempre a classe empacotadora? É, obviamente, iria receber alguns bugs fora do caminho cedo, mas quais são as desvantagens para isso? Ele afeta o desempenho ou consumo de memória do aplicativo? Há algum sorrateira pegadinhas?

Foi útil?

Solução

Usando os tipos de caixas faz ter ambos os problemas de desempenho e de memória.

Ao fazer comparações (por exemplo (i == 10)), java tem que unbox o tipo antes de fazer a comparação. Mesmo usando i.equals(TEN) usa uma chamada de método, que é mais caro e (IMO) mais feio do que a sintaxe ==.

memória Re, o objeto tem que ser armazenado na pilha (que também leva um golpe no desempenho), bem como armazenar o valor em si.

A sorrateira pegadinha? i.equals(j) quando i é null.

Eu sempre uso os primitivos, exceto quando se pode ser null, mas sempre verificar null antes da comparação nesses casos.

Outras dicas

Em primeiro lugar, a mudança de usando um primitivo ao uso de um objeto apenas para obter a capacidade de defini-lo como nulo é provavelmente uma decisão de design ruim. Muitas vezes eu tenho argumentos com os meus colegas de trabalho sobre se ou não nulo é um valor de sentinela, e minha opinião é geralmente que não é (e, portanto, não deve ser proibida como valores sentinela deve ser), mas neste caso particular, você está indo fora de sua maneira de usá-lo como um valor de sentinela. Por favor, não. Criar um booleano que indica se ou não o seu inteiro é válido, ou criar um novo tipo que envolve o boolean e inteiro juntos.

Geralmente, quando se utiliza versões mais recentes do Java, eu acho que eu não precisa criar explicitamente ou elenco para as versões de objetos de primitivos por causa do apoio auto-boxing que foi adicionado algum tempo em 1.5 (talvez 1,5 si).

Eu sugiro usar primitivas de todo o tempo a menos que você realmente tem o conceito de "null".

Sim, a VM não autoboxing e tudo isso agora, mas pode levar a alguns casos realmente estranhas onde você poderá obter uma exceção de ponteiro nulo em uma linha de código que você realmente não esperar, e você tem que começar fazer verificações nulos em cada operação matemática. Você também pode começar a receber alguns comportamentos não-óbvias, se você começar a misturar tipos e obtendo comportamentos estranho autoboxing.

Para float / dobra você pode tratar NaN como nula, mas lembre-se que NaN! = NaN então você ainda precisa cheques especiais como! Float.isNaN (x).

Seria muito bom se houvesse coleções que apoiaram os tipos primitivos em vez de ter que perder o tempo / sobrecarga de boxe.

No seu exemplo, a instrução if será ok até que você passar por cima de 127 (como Integer autoboxing irá armazenar em cache valores até 127 e retornar a mesma instância para cada número até este valor)

Por isso, é pior do que você apresentá-la ...

if( i == 10 )

vai funcionar como antes, mas

if( i == 128 )

falhará. É por razões como esta que eu sempre criar explicitamente objetos quando eu precisar deles, e tendem a ficar com variáveis ??primitivas se possível

tipos Ti java POD estão lá por um motivo. Além da sobrecarga, você não pode fazer operações normais com os objetos. Um Integer é um objeto, que precisam ser alocados e lixo coletado. Um int não é.

Se esse valor pode ser vazio, você pode achar que em seu projeto que você está na necessidade de algo mais.

Existem duas possibilidades - ou o valor são dados apenas (o código não vai agir de forma diferente se for preenchido ou não), ou ele está realmente indicando que você tem dois tipos diferentes de objeto aqui (o código age de forma diferente se houver um valor do que um nulo)

Se for de dados apenas para a exposição / armazenamento, você pode considerar o uso de uma verdadeira DTO - um que não tê-lo como membro de primeira classe em tudo. Aqueles geralmente terá uma maneira de verificar para ver se um valor foi definido ou não.

Se você verificar o nulo em algum momento, você pode querer estar usando uma subclasse porque quando há uma diferença, geralmente há mais. Pelo menos você quer uma maneira melhor para indicar a sua diferença do que "se primitiveIntValue == null", que não faz realmente qualquer coisa média.

Não ligue a não-primitivas apenas para obter esta facilidade. Use um booleano para indicar se o valor foi definido ou não. Se você não gosta que a solução e você sabe que seus inteiros será em algum limite razoável (ou não se preocupam com a falha ocasional) use um valor específico para indicar 'não inicializado', como Integer.MIN_VALUE. Mas isso é uma solução muito menos seguro do que o booleano.

Quando você chegou a esse 'Mais tarde' ponto, um pouco mais de trabalho necessário para ser realizado durante a refatoração. Use primitivos quando possível. (Período de Capital) Então faça POJOs se mais funcionalidade é necessária. Os classe empacotadora, na minha opinião, são mais utilizados para dados que precisam viajar por todo o fio, ou seja, aplicativos em rede. Permitindo nulos como valores aceitáveis ??provoca dores de cabeça como um sistema 'cresce'. Para tanto código desperdiçado ou perdido, guardando o que deve ser comparações simples.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top