É uma má prática criar novos objetos sem armazená-los?

23

Eu vi objetos criados no código Java sem armazenar uma referência ao objeto. Por exemplo, em um plug-in do eclipse, eu vi um SWT Shell criado assim:

new Shell();

Esse novo objeto Shell não é armazenado em uma variável, mas permanecerá referenciado até que a janela seja descartada, o que [acredito?] Acontece por padrão quando a janela é fechada.

É uma má prática criar objetos como esse sem armazenar uma referência a eles? Ou a biblioteca foi mal projetada? E se eu não precisar de uma referência, mas quiser apenas os "efeitos colaterais" do objeto? Devo armazenar uma referência de qualquer maneira?

ATUALIZAR:

É certo que meu exemplo acima é ruim. Embora eu tenha visto elementos da interface do usuário criados assim, a criação de um SWT Shell como esse provavelmente não faria sentido, porque você precisa chamar o método open na instância do Shell. Existem exemplos melhores fornecidos pelo aix , como os seguintes no tutorial sobre simultaneidade Java :

(new HelloThread()).start();

Essa prática é vista em muitos contextos, então as questões permanecem. É uma boa prática?

Botões840
fonte
2
Qual seria o sentido de armazenar a referência?
Daniel R Hicks
(Provavelmente seria melhor, do ponto de vista conceitual, ter um método estático, como Shell.createTopLevelShell()ou o que quer, vs usando um construtor neste caso, mas funcionalmente há pouca diferença..)
Daniel R Hicks
Essa pergunta é sobre a prática de criar objetos sem se referir a eles, criar classes que exigem essa prática ou é especificamente sobre a maneira como o SWT usa esse tipo de padrão?
precisa
1
Os objetos SWT devem ser dispose()d: Regra 1: se você o criou, você o descarta. eclipse.org/articles/swt-design-2/swt-design-2.html
jbindel
2
Eu usaria uma variável para manter uma referência para fins de depuração. Se você tiver um ponto de interrupção nesse método, poderá fazer com que o depurador consulte o objeto por meio da variável local. Sem a referência, tenho certeza de que é possível, mas provavelmente muito mais difícil.
Martin York

Respostas:

12

Há um elemento de preferência pessoal nisso, mas acho que não armazenar a referência não é necessariamente uma má prática.

Considere o seguinte exemplo hipotético:

new SingleFileProcessor().process(file);

Se um novo objeto de processador precisar ser criado para cada arquivo e não for necessário após a process()chamada, não há sentido em armazenar uma referência a ele.

Aqui está outro exemplo, retirado do tutorial de simultaneidade Java :

(new HelloThread()).start();

Eu já vi muitos outros exemplos quando a referência não é armazenada e parece perfeitamente correta para meus olhos, como:

String str = new StringBuilder().append(x).append(y).append(z).toString();

(O StringBuilderobjeto não é mantido.)

Existem padrões semelhantes envolvendo common.lang's HashCodeBuilderet al.

NPE
fonte
2
@ BalusC: Com respeito, não vejo o que o torna suspeito e de que maneira ter um método de fábrica é melhor (suponho que seu exemplo seja análogo ao meu, e getInstance()é uma fábrica e não um singleton).
NPE
Cabe à fábrica usar um singleton ou não. O interlocutor da fábrica não deve pensar muito sobre isso.
Donal Fellows
No seu exemplo, a instância FileProcessor (presumivelmente) não é necessária quando a instrução estiver concluída, enquanto no exemplo do OP a instância do Shell é (escondida) referenciada por outro objeto, e essa referência (e, portanto, o objeto do Shell) persiste além do duração da declaração.
Daniel R Hicks
@BalusC: FileProcessor pode ter métodos adicionais para alterar o comportamento de process.
Kevin 'cline em
7

Se você não precisar de uma referência ao objeto criado, não a segure. É simples assim.

Mike Baranczak
fonte
5

Em geral, é uma boa prática liberar referências o mais rápido possível. Não vejo diferença entre:

HelloThread thread = new HelloThread();
thread.start();
// where thread is never used for the rest of the method

e

(new HelloThread()).start();

No que diz respeito ao código, você está evitando o uso de um nome de variável, o que pode ser positivo. O compilador JIT geralmente é inteligente o suficiente para reconhecer que pode coletar lixo do encadeamento após seu último uso, portanto, provavelmente não há diferença do ponto de vista de desempenho.

O único problema real a ser evitado é o Código no Antipadrão do Construtor , mas não é disso que você está perguntando.

StriplingWarrior
fonte
3

Isso pode ser ruim se você estiver usando o SWT, porque é preciso limpar depois de si mesmo (chamando o método dispose ()). Mas para outras classes (não SWT), tudo bem.

Aqui está um artigo sobre o gerenciamento de recursos do sistema operacional

Alex
fonte
Referências circulares não impedem que objetos sejam coletados como lixo em Java. Qualquer Java VM moderna determina se os objetos podem ser GCable com base na possibilidade de serem alcançados e não usam a contagem de referência.
jbindel
2
Na verdade, ele não usa contagem de referência. Mas o SWT é um caso especial em que precisamos chamar dispose (), embora não seja necessário chamar nenhum reter () primeiro.
Alex
Eu pretendia me referir apenas ao caso não-SWT.
jbindel
Aqui está um artigo sobre o gerenciamento de recursos do sistema operacional eclipse.org/articles/swt-design-2/swt-design-2.html
Alex
2
Nesse caso, edite sua resposta para remover a declaração sobre "impossível para o GC", pois é enganosa.
Donal Fellows
1

Primeiro de tudo, você vai incomodar as pessoas que aprenderam C ou C ++ antes de Java. Vou deixar isso como um exercício para o leitor decidir se é um profissional ou um trapaceiro.

Embora certamente existam situações em que os objetos são projetados para durar muito pouco tempo, na maioria das vezes, se algo é complexo o suficiente para criar um objeto, é complexo o suficiente para ter boas razões para manter uma referência, portanto, não pelo menos, um aviso para verificar se você perdeu alguma coisa.

Por exemplo, em um tutorial, ninguém se preocupa em manter uma referência de encadeamento, mas na vida real, se algo demorar o suficiente para que você queira gerar um encadeamento, geralmente levará tempo suficiente para que você possa cancelar o encadeamento. Ou, se tiver vida mais curta, você normalmente gera vários tópicos que deseja joinantes de continuar. Ou você deseja garantir que a criação do encadeamento seja bem-sucedida. Ou você deseja garantir que o encadeamento termine corretamente antes de sair. Você entendeu a foto.

Karl Bielefeldt
fonte
2
Se preocupar com programadores irritantes de outras línguas é realmente a primeira preocupação?
precisa saber é o seguinte
Isso torna uma questão de legibilidade / familiaridade / estilo, dependendo da composição da sua equipe, porque é um estilo que muitas pessoas carregam. Mesmo as pessoas que nunca programaram em C ++ costumam adotar estilos de seus mentores que o fizeram.
Karl Bielefeldt