with try the force examples close catch java try-with-resources

java - the - ¿Por qué try-with-resource requiere una variable local?



try with resources java (4)

Con referencia a mi pregunta ¿ Hay algún riesgo en un envoltorio de cierre automático para java.util.concurrent.locks.Lock? Me pregunto por qué trh try-with-resource requiere una variable local con nombre .

Mi uso actual es el siguiente:

try (AutoCloseableReentrantReadWiteLock.Lock l = _lock.writeLock()) { // do something }

La variable l no se utiliza dentro del bloque try y solo contamina el espacio de nombres. De lo que puedo recordar, la declaración de C# análoga no requiere una variable local con nombre.

¿Hay alguna razón por la que no se haya admitido lo siguiente, con una variable local anónima que se cierre al final del bloque de prueba?

try (_lock.writeLock()) { // do something }


Creo que la incapacidad para usar la variable local fue el desencadenante de try-with-resource.

Antes de java 1.7 tenías que escribir algo como esto:

InputStream in = null; try { in = ....; } finally { if (in != null) { in.close(); } }

Hay 2 desventajas aquí:

  1. finally bloque es molesto y tiene que ser seguro para todos los recursos de cierre
  2. Debemos declarar los recursos fuera del bloque para poder acceder a ellos en el bloque final. Por lo tanto, ampliamos el alcance donde las variables son accesibles, lo que es una mala práctica.

La sintaxis Try-with-resource resuelve ambos problemas:

  1. finally bloque no es necesario en absoluto.
  2. La variable de recurso permanece accesible solo en el bloque de try , es decir, donde debería ser conocida.

Es por esto que el recurso de cierre debe ser local. De lo contrario, una de las principales desventajas de la sintaxis de intentar con recursos es "deshabilitada".


El enlace en el comentario de @McDowell revela la respuesta correcta en un comentario de una publicación de blog de Joe Darcy, quien dirigió la Especificación de la tecnología de Java que introdujo la declaración try-with-resources:

De vuelta en JDK 7, comenzamos con una construcción try-with-resources como la que permitía usar una expresión general para el recurso, incluida una llamada a un método. Sin embargo, el grupo de expertos encontró en la revisión preliminar inicial ( http://jcp.org/aboutJava/communityprocess/edr/jsr334/index.html ) que

"Un posible cambio futuro [en el estado de prueba con recursos] es eliminar el soporte para que un recurso se especifique como una expresión general. Las complejidades de implementación y especificación no triviales surgen al permitir el uso de una expresión general como recurso. Una expresión restringida que podría ser un identificador o un PrimaryNoNewArray puede ser suficiente. Incluso la restricción más severa de solo permitir un identificador puede proporcionar casi toda la utilidad adicional de permitir una expresión completa (forzar la declaración de una nueva variable de recursos) en una implementación marginal mucho menor y impacto de la especificación ".

Al final de JDK 7, lo que queríamos era una declaración de variable nueva para el recurso o una variable final / efectiva existente. Solo tuvimos tiempo de proporcionar el primero en 7; en 9, estamos proporcionando este último también.


Entre los casos de uso que estaban considerando, la mayoría necesitaría acceder al recurso dentro del bloque, por ejemplo, abrir archivo - leer / escribir archivo - cerrar archivo. No habrían tomado esta decisión de diseño si hubieran pensado que hay muchos casos de uso donde la variable local no se utiliza.

En cuanto a por qué Lock no se puede cerrar automáticamente, creo que a Doug Lea no le preocupa demasiado la cuestión de la sintaxis, se centra en resolver el problema difícil. Otros siempre pueden agregar azúcar de sintaxis a sus utilidades.

De cara al futuro, try-with-resource probablemente pasará de moda, reemplazado por lambda. Por ejemplo

lock.withLock( ()->{ execute-while-holding-the-lock; } );


Por mucho que quisiera que no fuera así, la razón detrás de esto es que el intento con recursos está destinado estrictamente para las operaciones en el elemento que debe eliminarse. Requiere una variable con nombre porque espera que hagas algo con esa variable mientras estés dentro del bloque. Supongo que es como si el compilador dijera "Si no planeas usar realmente el recurso, ¿por qué haces una prueba con recursos?"

Ahora, tú y yo sabemos muy bien que no queremos usar el recurso en realidad: más bien, solo queremos asegurarnos de que esté cerrado cuando hayamos terminado con él para que no haya desarrolladores que estén bloqueando el sistema. Pero como muchas otras cosas, tuvieron que tomar decisiones de diseño y estar en minoría, no obtuvimos la función.