Ist es eine schlechte Praxis, neue Objekte zu erstellen, ohne sie zu speichern?

23

Ich habe Objekte gesehen, die in Java-Code erstellt wurden, ohne einen Verweis auf das Objekt zu speichern. In einem Eclipse-Plugin habe ich beispielsweise eine SWT-Shell gesehen, die folgendermaßen erstellt wurde:

new Shell();

Dieses neue Shell-Objekt wird nicht in einer Variablen gespeichert, sondern es wird solange referenziert, bis das Fenster freigegeben wird. Dies geschieht standardmäßig, wenn das Fenster geschlossen wird.

Ist es eine schlechte Praxis, solche Objekte zu erstellen, ohne einen Verweis darauf zu speichern? Oder war die Bibliothek schlecht gestaltet? Was ist, wenn ich keine Referenz benötige, sondern nur die "Nebenwirkungen" des Objekts sehen möchte? Sollte ich trotzdem eine Referenz speichern?

AKTUALISIEREN:

Zugegeben, mein obiges Beispiel ist schlecht. Während ich solche UI-Elemente gesehen habe, wäre das Erstellen einer solchen SWT-Shell wahrscheinlich sinnlos, da Sie die open-Methode für die Shell-Instanz aufrufen müssen. Es gibt bessere Beispiele von aix, wie zum Beispiel die folgenden aus dem Java-Tutorial zur Parallelität :

(new HelloThread()).start();

Diese Praxis wird in vielen Zusammenhängen gesehen, daher bleiben die Fragen offen. Ist es eine gute Übung?

Buttons840
quelle
2
Was wäre der Sinn der Speicherung der Referenz?
Daniel R Hicks
(Aus konzeptioneller Sicht wäre es wahrscheinlich besser, eine statische Methode wie Shell.createTopLevelShell()oder was auch immer zu haben, als in diesem Fall einen Konstruktor zu verwenden. Aber funktional gibt es kaum einen Unterschied.)
Daniel R Hicks
Handelt es sich bei dieser Frage um das Erstellen von Objekten ohne Verweis auf diese, das Erstellen von Klassen, die diese Vorgehensweise erfordern, oder speziell um die Art und Weise, wie SWT diese Art von Muster verwendet?
StriplingWarrior
1
SWT-Objekte müssen dispose()d sein: Regel 1: Wenn Sie sie erstellt haben, entsorgen Sie sie. eclipse.org/articles/swt-design-2/swt-design-2.html
jbindel
2
Ich würde eine Variable verwenden, um eine Referenz für Debugging-Zwecke zu halten. Wenn Sie in dieser Methode einen Haltepunkt haben, können Sie den Debugger veranlassen, das Objekt über die lokale Variable abzufragen. Ohne den Hinweis bin ich sicher, dass es möglich, aber wahrscheinlich viel schwieriger ist.
Martin York

Antworten:

12

Es gibt ein persönliches Präferenzelement, aber ich denke, dass es nicht unbedingt eine schlechte Praxis ist, die Referenz nicht zu speichern.

Betrachten Sie das folgende hypothetische Beispiel:

new SingleFileProcessor().process(file);

Wenn für jede Datei ein neues Prozessorobjekt erstellt werden muss und nach dem process()Aufruf nicht mehr benötigt wird , macht es keinen Sinn, einen Verweis darauf zu speichern.

Hier ist ein weiteres Beispiel aus dem Java Concurrency Tutorial :

(new HelloThread()).start();

Ich habe viele andere Beispiele gesehen, bei denen die Referenz nicht gespeichert ist und die für mein Auge völlig in Ordnung sind, wie zum Beispiel:

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

(Das StringBuilderObjekt wird nicht behalten.)

Es gibt ähnliche Muster, an denen common.lang's HashCodeBuilderet al.

NPE
quelle
2
@BalusC: In Bezug auf Respekt sehe ich nicht, was es fischig macht und inwiefern es besser ist, eine Factory-Methode zu haben (ich nehme an, Ihr Beispiel ist analog zu meinem und getInstance()ist eine Factory und kein Singleton).
NPE
Es liegt an der Fabrik, ob ein Singleton verwendet wird oder nicht. Anrufer der Fabrik sollten nicht zu viel darüber nachdenken.
Donal Fellows
In Ihrem Beispiel wird die FileProcessor-Instanz (vermutlich) nach Abschluss der Anweisung nicht mehr benötigt, wohingegen im OP-Beispiel die Shell-Instanz (unter den Deckeln) von einem anderen Objekt referenziert wird und diese Referenz (und damit das Shell-Objekt) über das hinaus besteht Dauer der Erklärung.
Daniel R Hicks
@BalusC: FileProcessor verfügt möglicherweise über zusätzliche Methoden, um das Verhalten von zu ändern process.
Kevin Cline
7

Wenn Sie nicht brauchen einen Verweis auf das erstellte Objekt, dann halten Sie nicht auf die Referenz. So einfach ist das.

Mike Baranczak
quelle
5

Im Allgemeinen empfiehlt es sich, Verweise so schnell wie möglich freizugeben. Ich sehe keinen Unterschied zwischen:

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

und

(new HelloThread()).start();

In Bezug auf den Code vermeiden Sie lediglich die Verwendung eines Variablennamens, was positiv sein kann. Der JIT-Compiler ist im Allgemeinen schlau genug, um zu erkennen, dass er den Thread nach seiner letzten Verwendung müllsammeln kann, sodass es vom Standpunkt der Leistung aus wahrscheinlich keinen Unterschied gibt.

Das einzige wirkliche Problem, das Sie vermeiden sollten, ist der Code im Konstruktor-Anti-Pattern , aber es hört sich nicht so an, als würden Sie danach fragen.

StriplingWarrior
quelle
3

Dies kann schlecht sein, wenn Sie SWT verwenden, da Sie dort nach sich selbst aufräumen müssen (Aufruf der dispose () -Methode). Aber für andere Klassen (nicht SWT) ist es ok.

Hier ist ein Artikel zum Verwalten von Betriebssystemressourcen

Alex
quelle
Zirkelverweise verhindern nicht, dass Objekte in Java durch Garbage-Collection gelöscht werden. Jede moderne Java-VM bestimmt, ob Objekte GC-fähig sind, basierend darauf, ob sie erreichbar sind, und verwendet keine Referenzzählung.
jbindel
2
In der Tat wird keine Referenzzählung verwendet. Aber SWT ist ein spezieller Fall, in dem wir dispose () aufrufen müssen, obwohl es nicht nötig ist, vorher retain () aufzurufen.
Alex
Ich wollte mich nur auf den Nicht-SWT-Fall beziehen.
jbindel
Hier ist ein Artikel über die Verwaltung von Betriebssystemressourcen eclipse.org/articles/swt-design-2/swt-design-2.html
Alex
2
Bearbeiten Sie in diesem Fall Ihre Antwort, um die irreführende Aussage zu "unmöglich für GC" zu entfernen.
Donal Fellows
1

Zuallererst ärgern Sie Leute, die C oder C ++ vor Java gelernt haben. Ich überlasse das dem Leser als Übung, um zu entscheiden, ob das ein Pro oder ein Contra ist.

Während es sicherlich Situationen gibt, in denen Objekte sehr kurzlebig sind, ist es die meiste Zeit, wenn etwas komplex genug ist, um ein Objekt zu erstellen, komplex genug, um gute Gründe zu haben, einen Verweis zu behalten, weshalb es nicht beibehalten werden sollte Dies ist zumindest eine Warnung, um zu überprüfen, ob Sie etwas verpasst haben.

In einem Tutorial kümmert sich zum Beispiel niemand darum, einen Thread-Verweis zu führen. Wenn jedoch im wirklichen Leben etwas so lange dauert, dass Sie einen Thread erzeugen möchten, dauert es normalerweise so lange, dass Sie den Thread abbrechen können. Wenn die Lebensdauer kürzer ist, laichen Sie normalerweise eine Reihe von Threads, die Sie benötigen, joinbevor Sie fortfahren. Oder Sie möchten sicherstellen, dass Ihre Thread-Erstellung tatsächlich erfolgreich war. Oder Sie möchten sicherstellen, dass der Thread sauber endet, bevor Sie ihn beenden. Du bekommst das Bild.

Karl Bielefeldt
quelle
2
Ist die Sorge um nervige Programmierer aus anderen Sprachen wirklich das erste Problem?
Buttons840
Je nach Zusammensetzung Ihres Teams ist dies eine Frage der Lesbarkeit, Vertrautheit und des Stils, da es sich um einen Stil handelt, den viele Menschen mit sich bringen. Sogar Leute, die noch nie in C ++ programmiert haben, übernehmen häufig Stile von ihren Mentoren, die dies taten.
Karl Bielefeldt