Czy tworzenie nowych obiektów bez ich przechowywania jest złą praktyką?

23

Widziałem obiekty utworzone w kodzie Java bez przechowywania odniesienia do obiektu. Na przykład we wtyczce Eclipse widziałem powłokę SWT utworzoną w następujący sposób:

new Shell();

Ten nowy obiekt Shell nie jest przechowywany w zmiennej, ale pozostanie przywoływany, dopóki okno nie zostanie usunięte, co [Wierzę?] Dzieje się domyślnie, gdy okno jest zamknięte.

Czy tworzenie takich obiektów bez przechowywania odniesienia do nich jest złą praktyką? A może biblioteka była źle zaprojektowana? Co jeśli nie potrzebuję referencji, a chcę tylko „efektów ubocznych” obiektu? Czy mimo to powinienem przechowywać referencje?

AKTUALIZACJA:

Wprawdzie mój powyższy przykład jest słaby. Chociaż widziałem elementy interfejsu użytkownika utworzone w ten sposób, tworzenie powłoki SWT prawdopodobnie byłoby bezcelowe, ponieważ musisz wywołać metodę otwartą w instancji powłoki. Istnieją lepsze przykłady podane przez aix, takie jak poniższe z samouczka Java o współbieżności :

(new HelloThread()).start();

Ta praktyka jest postrzegana w wielu kontekstach, więc pytania pozostają. Czy to dobra praktyka?

Przyciski 840
źródło
2
Jaki byłby sens przechowywania referencji?
Daniel R Hicks,
(Prawdopodobnie byłoby lepiej, z konceptualnego punktu widzenia, mieć metodę statyczną taką jak Shell.createTopLevelShell()lub cokolwiek innego, niż użycie konstruktora w tym przypadku. Ale funkcjonalnie nie ma różnicy.)
Daniel R Hicks
Czy to pytanie dotyczy praktyki tworzenia obiektów bez odwoływania się do nich, tworzenia klas, które wymagają tej praktyki, czy też konkretnie dotyczy sposobu, w jaki SWT używa tego rodzaju wzorca?
StriplingWarrior
1
Obiektami SWT muszą być dispose()d: Reguła 1: Jeśli go utworzyłeś, pozbędziesz się go. eclipse.org/articles/swt-design-2/swt-design-2.html
jbindel
2
Użyłbym zmiennej do przechowywania referencji do celów debugowania. Jeśli masz punkt przerwania w tej metodzie, możesz poprosić debugger o wysłanie zapytania do obiektu za pomocą zmiennej lokalnej. Bez odniesienia jestem pewien, że jest to możliwe, ale prawdopodobnie dużo trudniejsze.
Martin York,

Odpowiedzi:

12

Jest w tym element osobistej preferencji, ale myślę, że nieprzechowywanie referencji niekoniecznie jest złą praktyką.

Rozważ następujący hipotetyczny przykład:

new SingleFileProcessor().process(file);

Jeśli dla każdego pliku należy utworzyć nowy obiekt procesora i nie jest on potrzebny po process() wywołaniu, nie ma sensu przechowywanie odwołania do niego.

Oto kolejny przykład zaczerpnięty z samouczka dotyczącego współbieżności Java :

(new HelloThread()).start();

Widziałem wiele innych przykładów, gdy odwołanie nie jest przechowywane, i które czytają mi doskonale, takie jak:

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

(The StringBuilder Obiekt nie jest przechowywany.)

Istnieją podobne wzorce dotyczące common.lang's HashCodeBuilderi in.

NPE
źródło
2
@BalusC: Z szacunkiem nie rozumiem, co sprawia, że ​​jest podejrzany i w jaki sposób lepsza jest metoda fabryczna (zakładam, że twój przykład jest analogiczny do mojego, i getInstance()jest fabryką, a nie singletonem).
NPE
Od producenta zależy, czy będzie to singleton, czy nie. Dzwoniący z fabryki nie powinien za bardzo o tym myśleć.
Donal Fellows
W twoim przykładzie instancja FileProcessor nie jest (prawdopodobnie) potrzebna, gdy instrukcja jest kompletna, podczas gdy w przykładzie OP instancja Shell jest (pod przykryciem) przywołana przez inny obiekt, a do tego odwołania (a zatem i obiektu Shell) pozostaje poza czas trwania wyciągu.
Daniel R Hicks,
@BalusC: FileProcessor może mieć dodatkowe metody zmiany zachowania process.
kevin cline
7

Jeśli nie potrzebujesz odwołania do utworzonego obiektu, nie trzymaj się tego odniesienia. To takie proste.

Mike Baranczak
źródło
5

Zasadniczo dobrą praktyką jest publikowanie referencji tak szybko, jak można je racjonalnie opublikować. Nie widzę różnicy między:

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

i

(new HelloThread()).start();

Jeśli chodzi o kod, po prostu unikasz używania nazwy zmiennej, co może być pozytywne. Kompilator JIT jest na ogół wystarczająco inteligentny, aby rozpoznać, że może odrzucić wątek po ostatnim użyciu, więc prawdopodobnie nie ma różnicy z punktu widzenia wydajności.

Jedynym prawdziwym problemem, którego należy unikać, jest kod w konstruktorze , ale nie brzmi to tak, jakbyś o to pytał.

StriplingWarrior
źródło
3

Może to być złe, jeśli używasz SWT, ponieważ musisz po sobie posprzątać (wywołując metodę dispose ()). Ale w przypadku innych klas (nie SWT) jest w porządku.

Oto artykuł o zarządzaniu zasobami systemu operacyjnego

Alex
źródło
Odwołania cykliczne nie zapobiegają odśmiecaniu obiektów w Javie. Każda nowoczesna maszyna wirtualna Java określa, czy obiekty są GCable na podstawie tego, czy są osiągalne, i nie korzysta z liczenia referencji.
jbindel
2
Rzeczywiście nie korzysta z liczenia referencji. Ale SWT jest szczególnym przypadkiem, w którym musimy wywołać metodę dispose (), chociaż nie ma potrzeby wywoływania żadnego parametru retain () w pierwszej kolejności.
Alex
Chciałem odnieść się tylko do sprawy spoza SWT.
jbindel
Oto artykuł o zarządzaniu zasobami systemu operacyjnego eclipse.org/articles/swt-design-2/swt-design-2.html
Alex
2
W takim przypadku edytuj swoją odpowiedź, aby usunąć stwierdzenie „niemożliwe do GC”, ponieważ jest mylące.
Donal Fellows
1

Przede wszystkim zirytujesz ludzi, którzy nauczyli się C lub C ++ przed Javą. Zostawię to jako ćwiczenie dla czytelnika, aby zdecydować, czy jest to zawodowiec, czy oszust.

Chociaż z pewnością istnieją sytuacje, w których obiekty są zaprojektowane tak, aby były krótkotrwałe, większość z nich czasu, jeśli coś jest wystarczająco złożone, aby stworzyć obiekt, jest wystarczająco złożone, aby mieć dobre powody, aby zachować odniesienie, więc nie należy go utrzymywać przynajmniej ostrzeżenie, aby dwukrotnie sprawdzić, czy coś przeoczyłeś.

Na przykład w samouczku nikt nie dba o zachowanie odniesienia do wątku, ale w prawdziwym życiu, jeśli coś trwa wystarczająco długo, abyś mógł założyć wątek, zwykle trwa to wystarczająco długo, aby móc anulować wątek. Lub jeśli żyją krócej, zwykle spawnujesz wiązkę wątków, którą będziesz chciał joinprzed kontynuowaniem. Lub chcesz się upewnić, że tworzenie wątków rzeczywiście się powiodło. Lub chcesz upewnić się, że nić kończy się czysto przed wyjściem. Dostajesz obraz.

Karl Bielefeldt
źródło
2
Czy martwienie się o irytujących programistów z innych języków jest naprawdę pierwszym problemem?
Buttons840
To sprawia, że ​​jest to kwestia czytelności / znajomości / stylu w zależności od składu twojego zespołu, ponieważ jest to styl, który wiele osób przenosi. Nawet ludzie, którzy nigdy nie programowali w C ++, często przyjmują style od swoich mentorów, którzy to zrobili.
Karl Bielefeldt,