java raii

¿Admite Java RAII/destrucción determinista?



(4)

Han pasado al menos 5 años desde que trabajé con Java, y en ese momento, cada vez que quería asignar un objeto que necesitaba limpieza (por ejemplo, sockets, identificadores de bases de datos), tenía que recordar agregar un bloque finally y llamar al método de limpieza ahí.

Por el contrario, en C ++ (u otros lenguajes donde los tiempos de vida de los objetos son deterministas, por ejemplo, Perl), el implementador de clase definiría una función de destrucción que realiza la limpieza cada vez que un objeto de esa clase sale del alcance. La ventaja de este enfoque es que el usuario del objeto no puede olvidarse de limpiarlo: el destructor se llama automáticamente, incluso si se lanza una excepción. Este enfoque se basa en el nombre bastante horrible de RAII: "La adquisición de recursos es la inicialización".

Según mi experiencia, hacer las cosas "de la manera RAII" me ha ahorrado una gran cantidad de gastos mentales en términos de no tener que preocuparme de si se producen desasignaciones de recursos y cuándo. Estamos considerando usar Java para un proyecto de tamaño mediano, y me pregunto si algún tipo de destrucción determinista se encuentra entre las muchas características nuevas agregadas al lenguaje desde la última vez que lo analicé. (Tengo la esperanza de que mi queja de que "Java no tiene RAII" fue reprendida en este hilo , pero hasta ahora no he podido encontrar ningún detalle buscando en Google.)

Entonces, si alguien pudiera dirigirme a un material introductorio sobre cómo hacerlo en Java, ¡sería genial!


El enfoque que tomo es usar un producto en capas (a veces un método estático simple) que se ocupa de la asignación de recursos. No desea que este tipo de asignación de recursos ensucie su programa.

Hay muchas bibliotecas que hacen esto. No es algo de lo que deba preocuparse en la mayoría de los casos.


EDITAR: La respuesta a continuación fue escrita a principios de 2009, cuando Java 7 todavía estaba en un gran cambio.

Si bien Java aún no tiene destrucción determinística, ganó una característica como la declaración de using C #: la declaración try-with-resources .

No, Java no ha cambiado en absoluto a ese respecto. Aún necesita usar try / finally.

Se ha discutido la posibilidad de agregar a Java el equivalente de la instrucción "using" de C # (que es azúcar sintáctico sobre try / finally), pero no creo que eso vaya a ser parte de Java 7. (La mayoría de las mejoras en el lenguaje parecen haberse descartado).

Vale la pena entender que hay razones por las que la destrucción determinista no se ha implementado en Java y .NET, por cierto, tiende a involucrar el recuento de referencias, que a) impacta el rendimiento yb) falla con referencias circulares. Brian Harry escribió un correo electrónico detallado sobre esto: se trata de .NET y tiene más de 8 años, pero vale la pena leerlo de cerca.


Nop. No hay ninguna posibilidad para asignar objetos en la pila. Cada Objeto se asigna en el montón y puede sobrevivir en cualquier bloque en el que se haya inicializado. O se puede recopilar a mitad de cuadra, dependiendo de los caprichos del poderoso Recolector de Basura.

Si está trabajando en el servidor, es posible que desee comprobar Java EE . No tiene nada que ver con RAII, pero sí tiene un sistema decente para administrar los ciclos de vida de objetos costosos como conexiones DB. Java EE 5 es realmente muy bueno para trabajar con muchos espacios problemáticos.


Hay un patrón que ayuda aquí. No es tan agradable como RAII basado en destructor, pero sí significa que la limpieza de recursos se puede mover a la biblioteca (para que no se te olvide llamar).

Se llama Execute Around, y se ha discutido aquí antes .

Curiosamente, veo a Jon Skeet interviniendo en ese hilo, pero él no lo mencionó aquí, ¡qué vergüenza, Jon! ¡Perdí la oportunidad de obtener algunos puntos de representante allí!

Por cierto, aunque estoy contento de que Brian Harry (vea el comentario de Jon, otra vez) se tomó la molestia de escribir el correo electrónico que lo hizo, y obviamente reflejó muchos de los pensamientos que entraron en el proceso, y estoy contento de haberlo hecho. "usarlo" en C # - No estoy de acuerdo con todas sus conclusiones. En particular, no veo por qué, si podemos tener uso, no podemos tener una manera de marcar un tipo como comportándose de esa manera sin "usar". Por supuesto, restringe el uso, pero también lo hace el "uso", y la mayoría de las veces es exactamente lo que desea. El problema con "usar" es que el código del cliente todavía tiene que recordar usarlo. Con C ++ estilo RAII es una propiedad del tipo. Un problema mucho mayor con "usar", o más exactamente con la expresión Dispose, es que es mucho más complicado y propenso a errores de lo que la mayoría de la gente cree que es correcto, principalmente por la posibilidad de que los objetos vuelvan de la muerte.