Desculpe se parecer muito rude, mas essa distinção não faz o menor sentido.
O que vc precisa é entender as diferenças entre eles, e aí analisar o que faz mais sentido ou não para cada caso.
O tipo primitivo ocupa menos espaço e em geral é mais eficiente (já que o wrapper precisa criar uma instância, vai ocupar espaço no heap, é mais um objeto pro GC gerenciar, etc).
O wrapper nem sempre se comporta da forma que você espera. Por exemplo, o código abaixo imprime false
:
Integer x = 1000;
Integer y = 1000;
System.out.println(x == y); // false
Curiosamente, se trocar o 1000
para 10
, aí dá true
. Isso porque os valores entre -128 e 127 são cacheados internamente, e aí eles sempre geram a mesma instância. Mas valores fora dessa faixa acabam criando uma nova instância.
Outra diferença é que um wrapper pode ser nulo. Ou seja, Integer x = null;
é válido (e qualquer tentativa de usá-lo dará um NullPointerException
), já int x = null;
nem compila. Existem situações em que pode ser necessário que o valor seja null
(por exemplo, em um campo opcional, o null
indicaria que ele não foi enviado, etc). Com primitivo, vc teria que usar artifícios como -1
para indicar que o valor é inválido (supondo que o método só trabalhe com números positivos), mas o “correto” depende de cada caso.
Um motivo em que seria “obrigatório” usar wrappers é quando você tem collections (List
, Set
e Map
), pois em Java não é possível ter um List<int>
(somente List<Integer>
). Aí não tem jeito, é uma limitação da linguagem e não tem pra onde fugir.
Tem também a questão da performance. Quando você usa um wrapper em contextos que esperam um primitivo (ou vice-versa), é feita uma conversão automática (o chamado autoboxing e unboxing). Por isso dá para adicionar um primitivo diretamente em uma lista (list.add(20)
) ou usar um Integer
diretamente em cálculos, a conversão é feita por baixo dos panos pra vc. Só que toda essa conversão tem seu custo, e dependendo do caso pode degradar a performance (e claro que deve ser avaliado caso a caso, para ver se isso faz diferença ou não para a aplicação).
Enfim, é isso tudo que deve ser avaliado em cada caso, pra saber qual usar. E aí tanto faz se é numa classe, método (estático ou não), no main
, etc.
Aliás, entender o que cada coisa faz, pra daí decidir quando usar um ou outro, vale para qualquer coisa em computação. As tais “boas práticas” não são leis imutáveis que devem ser seguidas cegamente, são no máximo recomendações. Mas vc sempre tem que avaliar o contexto pra saber quando segui-las ou não, e pra isso precisa entender bem o funcionamento de cada coisa.