java - what - use try with resources or close this fileinputstream in a finally clause
Patrón de diseño RAII en Java (2)
1. ¿Mi entendimiento es correcto?
Más o menos. Sí, puede usar try-with-resources de esta manera y sí, es semánticamente comparable a RAII. La diferencia es que no hay destrucción ni desasignación , solo una llamada de método.
Es raro encontrar objetos escritos solo para envolver algo de lógica de administración de recursos, por ejemplo:
import java.util.concurrent.locks.Lock;
public class Guard implements AutoCloseable {
private final Lock lock;
public Guard(Lock lock) {
this.lock = lock;
lock.lock();
}
@Override
public void close() {
lock.unlock();
}
}
try(Guard g = new Guard(myLock)) {
// do stuff
}
Si está trabajando con otros programadores, es posible que tenga que explicar lo que significa para algunas personas, pero personalmente no veo ningún problema si flota su barco.
Lo que no recomendaría es escribir código extraño como
try(AutoCloseable a = () -> lock.unlock()) {
lock.lock();
// do stuff
}
que es seguro generar WTFs en la revisión del código.
2. ¿Qué tan arriesgado es ignorar estas advertencias?
No arriesgado La advertencia es en realidad sólo una notificación. Ya sabes, por si no lo sabías.
Para deshacerte de la advertencia puedes intentar:
try(@SuppressWarnings("unused")
MyResource myVar = new MyResource())
O tal vez vea también ''¿Cómo hacer que * ant * no imprima las advertencias de javac?'' .
Un IDE debería darle la opción de suprimir una advertencia en particular ya sea globalmente o solo para una sola declaración (sin la anotación).
Proveniente de un fondo de C ++, soy un gran fanático del patrón RAII. Lo he usado ampliamente para manejar la administración de memoria y la administración de bloqueos junto con otros casos de uso.
Con Java 1.7 veo que puedo usar el patrón try-with-resources para crear un patrón RAII.
Creé una aplicación de ejemplo usando RAII y funciona, pero veo advertencias del compilador desde Java.
Aplicación de muestra
try(MyResource myVar = new MyResource(..))
{
//I am not using myVar here
}
Me sale los siguientes errores
warning: [try] auto-closeable resource node is never referenced in body of corresponding try statement
Entiendo la advertencia, implica que debería haber usado la variable dentro del bloque try, que realmente no necesito hacer todo el tiempo.
Viendo esto, asumo que Java realmente no tiene un verdadero soporte para RAII y podría haber usado mal la función que era solo para la Gestión de Recursos y no exactamente un equivalente de RAII en C ++.
Par de preguntas:
- ¿Mi entendimiento es correcto?
- ¿Qué tan arriesgado es ignorar estas advertencias?
- ¿Cómo puedo ignorar estas advertencias a través de hormigas?
- ¿Hay una manera simple para que yo pueda superar esto?
para 4 estoy pensando en dividir la llamada del constructor en un constructor más simple y un método de instancia como este
try(MyResource myVar = new Resource())
{
myvar.Initialize()
....
}
Lo que resuelve los problemas del compilador, pero elimina la esencia del diseño similar a RAII.
Para ampliar en la respuesta de Radiodef. Creo que RAII con try-with-resources es un patrón totalmente aceptable para Java. Pero para suprimir realmente la advertencia.
- debe utilizar
@SuppressWarnings("try")
lugar de@SuppressWarnings("unused")
. - Y agregar anotación en el método en lugar de declaración de variable
Un ejemplo con los puntos anteriores aplicados:
@SuppressWarnings("try")
void myMethod1() {
try(MyResource myVar = new MyResource(..)) {
//I am not using myVar here
}
}
Ampliando el propio patrón. Lo he usado ampliamente para administrar bloqueos de lectura-escritura y funcionó muy bien.
En mi código, he usado el truco para desbloquear de forma preventiva algún recurso para aumentar la concurrencia, como esto:
try (Guard g1 = new Guard(myLock1)) {
someStuffThatRequiresOnlyLock1();
try (Guard g2 = new Guard(myLock2)) {
someStuffThatRequiresBothLocks();
if (isSomething) {
g1.close();
someMoreSuffThatRequiresOnlyLock2()
} else {
someMoreSuffThatRequiresBothLocks();
}
}
}
Los bloqueos siempre se adquieren en el mismo orden, pero el desbloqueo se realiza según sea necesario, dejando tanto espacio para el procesamiento simultáneo como sea posible. El ajuste para que funcione con los bloqueos de lectura-escritura es modificar la clase Guard para permitir cierres repetidos:
public class Guard implements AutoCloseable {
private final Lock lock;
private boolean isClosed = false;
public Guard(Lock lock) {
this.lock = lock;
lock.lock();
}
@Override
public void close() {
if (!isClosed) {
isClosed = true;
lock.unlock();
}
}
}