Quando usar a classe de wrapper e o tipo primitivo

Respostas:

69

Outros mencionaram que certas construções, como Collectionsrequerem objetos e que os objetos têm mais sobrecarga do que suas contrapartes primitivas (memória e boxing).

Outra consideração é:

Pode ser útil inicializar objetos nullou enviar nullparâmetros para um método / construtor para indicar o estado ou função. Isso não pode ser feito com primitivos.

Muitos programadores inicializam os números como 0 (padrão) ou -1 para significar isso, mas dependendo do cenário, isso pode ser incorreto ou enganoso.

Isso também definirá o cenário para NullPointerExceptionquando algo estiver sendo usado incorretamente, o que é muito mais amigável para o programador do que algum bug arbitrário no futuro.

pstanton
fonte
15
"Pode ser útil inicializar objetos como nulos". Não pode ser útil porque está incorreto; se o campo for opcional, você deve indicar isso explicitamente.
Eddie Jamsession
8
lol @EddieJamsession obrigado, eu nunca irei inicializar com null novamente. (pfffft)
pstanton 01 de
@EddieJamsession Se a inicialização de objetos como nulo como uma forma de indicar falha ao definir o valor real falhou, de que outra forma você proporia para detectar esse problema? Oh, acabei de perceber enquanto digito isto: exceções. Uma NullPointerException é muito genérica; seria melhor usar exceções personalizadas muito específicas para indicar o que deu errado. Bom, farei isso de agora em diante ...
klaar
1
@EddieJamsession Depois de ler sobre o assunto, descobri o conceito de um objeto opcional. Certo.
klaar
18

Geralmente, você deve usar tipos primitivos, a menos que precise de um objeto por algum motivo (por exemplo, para colocar em uma coleção). Mesmo assim, considere uma abordagem diferente que não exija um objeto se você quiser maximizar o desempenho numérico. Isso é recomendado pela documentação e este artigo demonstra como a caixa automática pode causar uma grande diferença de desempenho.

Matthew Flaschen
fonte
3
o impacto no desempenho não é tão grande a ponto de a legibilidade / confiabilidade do código ficar em segundo plano.
pstanton
2
Primeiro, usar primitivos de maneira apropriada não tornará seu código ilegível. Em segundo lugar, o impacto no desempenho é significativo em alguns casos. É absurdo dizer que nunca é.
Matthew Flaschen,
1
@pstanton: explique como Integeré mais legível do que int.
Stephen C,
Em muitos casos, Integer não é mais legível que int e, nesses casos, sempre usarei int, ou se eu souber que uma determinada variável NUNCA será nula, usarei int porque int é, como você apontou, um pouco mais eficiente. No entanto, em muitos casos, é mais fácil para outro programador entender o estado de uma variável quando um objeto é usado, pois ele pode ser inicializado como nulo para significar que não está pronto. Por exemplo, se você tiver um registro de banco de dados não salvo que possui um id numérico de incremento único, esse id deve ser 0, -1 ou nulo antes de ser atribuído um id válido? Nesse caso, os objetos são melhores.
pstanton
em relação ao desempenho - em casos especiais, o impacto no desempenho pode ser significativo, ou seja, se você estiver criando uma grande quantidade desses objetos muito rapidamente ou se muitos, muitos deles se acumularem ao longo de um período de tempo. No entanto, espero que um programador decente seja capaz de identificar esses casos especiais, evitando ou corrigindo de acordo. Eu nunca disse que NUNCA é significativo, porém de modo geral não é.
pstanton
12

Em minha opinião, se meus membros de classe são variáveis ​​de invólucro, isso não depende de valores padrão, o que é um comportamento amigável do desenvolvedor.

1

class Person {
   int SSN ; // gets initialized to zero by default 
}

2

class PersonBetter {
  Integer SSN; //gets initialized to null by default
}

No primeiro caso, você não pode manter o valor SSN não inicializado. Pode doer se você não estiver verificando se o valor foi definido antes de tentar usá-lo.

No segundo caso, você pode manter o SSN inicializado com nulo. O que pode levar a NullPointerException, mas é melhor do que inserir inadvertidamente valores padrão (zero) como SSN no banco de dados sempre que você tentar usá-lo sem inicializar o campo SSN.

Cody
fonte
3
O padrão do construtor deve contornar isso. Nesse cenário, você PersonBuildercria um que lança uma exceção se o SSN não for definido antes de chamar "build" para obter a Personinstância. Acho que esse tipo de coisa é excessivo, mas é o que a linguagem Java promove para padrões adequados.
Sandy Chapman
8

Eu só usaria os tipos de invólucro se necessário.

Em usá-los você não ganha muito, além do fato de que eles são Objects.

E você perde sobrecarga no uso de memória e tempo gasto boxing / unboxing.

jjnguy
fonte
4
você pode não ganhar muito, mas também não perde muito. a menos que você esteja rodando em um palm pilot de 1990.
pstanton
O fato de serem objetos também lhes dá muito mais contexto e encapsulamento do que um primitivo puro. Portanto, você pode realmente ganhar muito, dependendo do objetivo desses primitivos e de onde eles estão sendo usados.
aberrant80 de
4

Praticamente encontrei uma situação em que o uso da classe wrapper pode ser explicado.

Eu criei uma classe de serviço que tinha uma longvariável de tipo

  1. Se a variável for do tipo long- quando não inicializada, será definida como 0 - isso será confuso para o usuário quando exibido na GUI
  2. Se a variável for do tipo Long- quando não inicializada, ela será configurada para null- este valor nulo não aparecerá na GUI.

Isso se aplica á Boolean também a onde os valores podem ser mais confusos quando usamos primitivos boolean(já que o valor padrão é falso).

Mohamed Afzal
fonte
3

As coleções são o caso típico de objetos de invólucro Java simples. No entanto, você pode considerar dar ao Wrapper um significado mais específico no código (objeto de valor).

IMHO, quase sempre há um benefício em usar objetos de valor quando se resume à legibilidade e manutenção do código. Encapsular estruturas de dados simples dentro de objetos quando eles têm certas responsabilidades geralmente simplifica o código. Isso é algo muito importante no design orientado a domínio .

É claro que existe o problema de desempenho, mas tendo a ignorar isso até ter a possibilidade de medir o desempenho com dados adequados e fazer ações mais direcionadas para a área problemática. Também pode ser mais fácil entender o problema de desempenho se o código também for fácil de entender.

Mattias Holmqvist
fonte
3

o desempenho de aplicativos que são dominados por cálculos numéricos pode se beneficiar muito com o uso de primitivas.

tipos primitivos, usa-se o operador ==, mas para wrapper a escolha preferida é chamar o método equals ().

"Tipos primitivos considerados prejudiciais" porque misturam "semântica procedural em um modelo orientado a objetos uniforme.

Muitos programadores inicializam os números como 0 (padrão) ou -1 para significar isso, mas dependendo do cenário, isso pode ser incorreto ou enganoso.

Loknath
fonte
1

Se você deseja usar coleções, você deve usar classes Wrapper.

Tipos primitivos são usados ​​para matrizes. Além disso, para representar dados que não têm comportamento, por exemplo, um contador ou uma condição booleana.

Desde o autoboxing, a fronteira "quando usar primitivo ou invólucro" tornou-se bastante confusa.

Mas lembre-se, Wrappers são objetos, então você obtém todos os recursos sofisticados do Java. Por exemplo, você pode usar a reflexão para criar objetos inteiros, mas não valores inteiros. As classes de wrapper também possuem métodos como valueOf.

Tom
fonte
Além de coleções, eu não deveria usar classes de wrapper? Que tal usá-lo para uma declaração comum como Integer i = new Integer (10); É bom fazer assim?
Gopi de
o autoboxing permite que você faça Inteiro i = 10;
Tom,
1
Não, Sri. Se você não tem o requisito de que eu seja um objeto, não o torne.
Matthew Flaschen,
O autoboxing irá desempacotar o i declarado acima para int i = 10 ou Integer i = 10?
Gopi de
3
int pi = novo inteiro (10); trabalho. Oi inteiro = 10; trabalho. int ni = nulo; não funciona. o LHS é convertido para o que o RHS exigir.
pstanton
0

Se você deseja criar um tipo de valor. Algo como ProductSKU ou AirportCode.

Quando um tipo primitivo (string em meus exemplos) define igualdade, você deseja substituir a igualdade.

Chris Missal
fonte
5
string não é um primitivo
pstanton
2
ainda existem boas razões para envolver um tipo de valor que contém uma string como o objeto base.
Chris Missal de
sua resposta simplesmente não faz sentido. não tenho certeza do que você está dizendo. Eu concordo com seu comentário, porém, as classes de wrapper são uma boa idéia se melhorarem a legibilidade.
pstanton
Tipos de valor ou objetos de valor devem ser criados e imutáveis. Por exemplo, não faria sentido criar um objeto "CountryCode" como: new CountryCode ("USA") e depois criar outro objeto da mesma forma, onde posteriormente serão diferentes. Eles são apenas strings para começar, mas têm um significado por trás deles. Ao usar strings, você pode modificá-los (acrescentando mais dados, etc), mas eles não seriam mais iguais. Veja este artigo para uma descrição melhor do que estou tentando explicar :) Espero que isso faça sentido c2.com/cgi/wiki?ValueObject
Chris Missal
0

Valores primitivos em Java não são objetos. Para manipular esses valores como objeto, o pacote java.lang fornece uma classe de invólucro para cada tipo de dados primitivo.

Todas as classes de Wrapper são finais. Os objetos de todas as classes de wrapper que podem ser iniciadas são imutáveis, o que significa que o valor no objeto de wrapper não pode ser alterado.

Embora a classe void seja considerada uma classe wrapper, ela não envolve nenhum valor primitivo e não pode ser iniciada. Ele não tem um construtor público, apenas denota um objeto de classe que representa a palavra-chave void.

Ahmad Sayeed
fonte