¿Es una mala práctica crear nuevos objetos sin almacenarlos?

23

He visto objetos creados en código Java sin almacenar una referencia al objeto. Por ejemplo, en un complemento de eclipse he visto un SWT Shell creado así:

new Shell();

Este nuevo objeto Shell no se almacena en una variable, pero permanecerá referenciado hasta que se elimine la ventana, lo que [creo?] Ocurre de manera predeterminada cuando se cierra la ventana.

¿Es una mala práctica crear objetos como este sin almacenar una referencia a ellos? ¿O fue la biblioteca mal diseñada? ¿Qué sucede si no necesito una referencia, pero solo quiero los "efectos secundarios" del objeto? ¿Debo guardar una referencia de todos modos?

ACTUALIZAR:

Es cierto que mi ejemplo anterior es pobre. Si bien he visto elementos de la interfaz de usuario creados de esta manera, crear un SWT Shell como este probablemente no tenga sentido porque debe llamar al método abierto en la instancia de Shell. Hay mejores ejemplos proporcionados por aix , como los siguientes del tutorial de concurrencia de Java :

(new HelloThread()).start();

Esta práctica se ve en muchos contextos, por lo que las preguntas permanecen. ¿Es una buena práctica?

Botones840
fuente
2
¿Cuál sería el punto de almacenar la referencia?
Daniel R Hicks
(Probablemente sería mejor, desde un punto de vista conceptual, tener un método estático como Shell.createTopLevelShell()o lo que sea, en lugar de usar un constructor en este caso. Pero funcionalmente hay poca diferencia.)
Daniel R Hicks
¿Se trata de la práctica de crear objetos sin referirse a ellos, crear clases que requieren esta práctica, o se trata específicamente de la forma en que SWT usa este tipo de patrón?
StriplingWarrior
1
Los objetos SWT deben ser dispose()d: Regla 1: si lo creó, lo dispone. eclipse.org/articles/swt-design-2/swt-design-2.html
jbindel
2
Usaría una variable para contener una referencia con fines de depuración. Si tiene un punto de interrupción en este método, puede hacer que el depurador consulte el objeto a través de la variable local. Sin la referencia, estoy seguro de que es posible, pero probablemente mucho más difícil.
Martin York

Respuestas:

12

Hay un elemento de preferencia personal para esto, pero creo que no almacenar la referencia no es necesariamente una mala práctica.

Considere el siguiente ejemplo hipotético:

new SingleFileProcessor().process(file);

Si es necesario crear un nuevo objeto de procesador para cada archivo, y no es necesario después de la process()llamada, no tiene sentido almacenar una referencia a él.

Aquí hay otro ejemplo, tomado del tutorial de concurrencia de Java :

(new HelloThread()).start();

He visto muchos otros ejemplos cuando la referencia no está almacenada, y eso se lee perfectamente bien para mí, como:

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

(El StringBuilderobjeto no se guarda).

Hay patrones similares que involucran common.lang's HashCodeBuilderet al.

NPE
fuente
2
@BalusC: Con respeto, no veo qué lo hace sospechoso y de qué manera es mejor tener un método de fábrica (supongo que su ejemplo es análogo al mío, y getInstance()es una fábrica y no un singleton).
NPE
Depende de la fábrica si usar un singleton o no. Quien llama a la fábrica no debería pensar demasiado en ello.
Donal Fellows
En su ejemplo, la instancia de FileProcessor (presumiblemente) no es necesaria una vez que se completa la declaración, mientras que en el ejemplo del OP, la instancia de Shell está (debajo de las cubiertas) referenciada por otro objeto, y esa referencia (y, por lo tanto, el objeto Shell) persiste más allá del duración de la declaración.
Daniel R Hicks
@BalusC: FileProcessor podría tener métodos adicionales para alterar el comportamiento de process.
Kevin Cline
7

Si no necesita una referencia al objeto creado, no se aferre a la referencia. Es tan simple como eso.

Mike Baranczak
fuente
5

En general, es una buena práctica publicar referencias lo más rápido posible. No veo diferencia entre:

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

y

(new HelloThread()).start();

En lo que respecta al código, solo está evitando el uso de un nombre de variable, lo que podría ser algo positivo. El compilador JIT es generalmente lo suficientemente inteligente como para reconocer que puede recolectar basura el subproceso después de su último uso, por lo que probablemente no haya diferencia desde el punto de vista del rendimiento.

El único problema real que debe evitarse es el Código en el Anti-Patrón de Constructor , pero no parece que eso sea lo que está preguntando.

StriplingWarrior
fuente
3

Esto podría ser malo si está utilizando SWT, porque allí tiene que limpiar después de usted mismo (llamando al método dispose ()). Pero para otras clases (no SWT) está bien.

Aquí hay un artículo sobre la administración de recursos del sistema operativo

Alex
fuente
Las referencias circulares no evitan que los objetos se recojan en Java. Cualquier máquina virtual Java moderna determina si los objetos son GCable en función de si son accesibles y no utiliza el recuento de referencias.
jbindel
2
De hecho, no utiliza el recuento de referencias. Pero SWT es un caso especial en el que necesitamos llamar a dispose (), aunque no es necesario llamar primero a ningún retención ().
Alex
Quise referirme solo al caso no SWT.
jbindel
Aquí hay un artículo sobre Administración de recursos del sistema operativo eclipse.org/articles/swt-design-2/swt-design-2.html
Alex
2
En ese caso, edite su respuesta para eliminar la afirmación sobre "imposible para GC", ya que es engañoso.
Donal Fellows
1

En primer lugar, vas a molestar a las personas que aprendieron C o C ++ antes de Java. Lo dejaré como un ejercicio para que el lector decida si es un profesional o un estafador.

Si bien hay situaciones en las que los objetos están diseñados para ser de corta duración, la mayoría de las veces si algo es lo suficientemente complejo como para crear un objeto, es lo suficientemente complejo como para tener buenas razones para mantener una referencia, por lo que no mantenerlo en como mínimo, una advertencia para verificar dos veces si se ha perdido algo.

Por ejemplo, en un tutorial a nadie le importa mantener una referencia de subproceso, pero en la vida real, si algo demora lo suficiente como para generar un subproceso, generalmente demora lo suficiente como para poder cancelar el subproceso. O si tiene una vida más corta, generalmente está generando un montón de hilos que querrá joinantes de continuar. O desea asegurarse de que la creación de su hilo realmente haya tenido éxito. O desea asegurarse de que el hilo finalice limpiamente antes de salir. Te dan la imagen.

Karl Bielefeldt
fuente
2
¿Preocuparse por los molestos programadores de otros idiomas es realmente la primera preocupación?
Botones840
Lo convierte en un problema de legibilidad / familiaridad / estilo dependiendo de la composición de su equipo, porque es un estilo que muchas personas llevan. Incluso las personas que nunca han programado en C ++ a menudo adoptan estilos de sus mentores que sí lo hicieron.
Karl Bielefeldt