¿Java tiene una declaración de uso?

107

¿Java tiene una declaración de uso que se puede usar al abrir una sesión en hibernación?

En C # es algo como:

using (var session = new Session())
{


}

Entonces, el objeto sale del alcance y se cierra automáticamente.

mrblah
fuente
4
"permitir definir un alcance para un objeto" Eso no es lo que usinghace. El alcance no es de por vida (y usingtampoco se trata de vida, estrictamente hablando, ya Disposeque no destruye la memoria de un objeto)
Joren
4
@Joren Tu comentario está siendo votado, pero me vendría bien un poco más de información. Usted es el que presenta la idea de "vida" y luego dice que no se trata de "vida". Alcance es el término utilizado en la definición de la biblioteca msdn, tal vez lo utilicé mal. ¿Cómo definiría el using statement.
Jla
1
El alcance se refiere al área en el código en el que puede hacer referencia a un identificador sin usar su nombre completo (variable local, tipo, nombre de método, etc.). La vida útil se refiere al tiempo en el que un objeto o variable es accesible. Ver blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren
2
Entonces, por ejemplo, si tiene una variable local y le asigna una instancia de tipo de valor, la vida útil de su valor terminará cuando finalice la vida útil de su variable. Pero si asignó un objeto y almacenó una referencia a él en un local, entonces la vida útil de ese objeto puede extenderse más allá de la vida útil de su almacenamiento, siempre que todavía haya alguna referencia al objeto en otro lugar. En cuanto a using, elimina automáticamente el objeto al final de su alcance, pero no desasigna el objeto; su vida útil no termina hasta que todas sus referencias hayan desaparecido.
Joren
1
posible duplicado de la palabra clave "using" en java
HaveNoDisplayName

Respuestas:

124

Java 7 introdujo la Gestión Automática de Bloques de Recursos que trae esta característica a la plataforma Java. Las versiones anteriores de Java no tenían nada parecido using.

Como ejemplo, puede usar cualquier variable que se implemente java.lang.AutoCloseablede la siguiente manera:

try(ClassImplementingAutoCloseable obj = new ClassImplementingAutoCloseable())
{
    ...
}

La java.io.Closeableinterfaz de Java , implementada por secuencias, se extiende automágicamente AutoCloseable, por lo que ya puede usar secuencias en un trybloque de la misma manera que las usaría en un usingbloque C # . Esto es equivalente a C # using.

A partir de la versión 5.0, Hibernate Sessions implementaAutoCloseable y puede cerrarse automáticamente en bloques ARM. En versiones anteriores de Hibernate Session no se implementóAutoCloseable . Por lo tanto, deberá estar en Hibernate> = 5.0 para poder usar esta función.

Asaf
fuente
1
"Afortunadamente" con Java 7 disponible ahora, esta respuesta ya no es cierta (y creo que los bloques ARM son exactamente lo que usingsí).
Joachim Sauer
@Joachim Sauer: Gracias. Actualicé mi respuesta para reflejar el paso del tiempo. Hasta el punto de que los bloques ARM son exactamente lo que hace el uso; en el momento en que escribí esta respuesta, me pareció que los bloques ARM tenían que ser bloques de prueba, mientras que el uso se puede aplicar a cualquier bloque arbitrario. Mirándolo ahora, parece que la palabra clave do se puede usar en Java para lograr esto. ¿Eso se agregó a la propuesta recientemente o me lo perdí la primera vez? Además, el OP preguntó específicamente sobre las sesiones de Hibernate. AFAIK: Hibernate Sessions aún no se implementa, AutoCloseablepor lo que aún no pueden usar ARM.
Asaph
1
No evento en 4.3 Hibernate NO implementa AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… ¿Supongo que depende de cada uno escribir su propio contenedor?
Andrei Rînea
1
La sesión no puede implementar AutoCloseable ya que Session.close () devuelve una conexión. Creo que este es un mal diseño, pero dudo que cambie alguna vez.
usr-local-ΕΨΗΕΛΩΝ
@ usr-local-ΕΨΗΕΛΩΝ Me imaginé que obligarían a cualquiera que use hibernación a cambiar a Java 7 si implementaran esa interfaz. AutoCloseableno existía antes de Java 7, ¿verdad?
Neil
31

Antes de Java 7 , no existía tal característica en Java (para Java 7 y versiones posteriores, consulte la respuesta de Asaph con respecto a ARM ).

Tenías que hacerlo manualmente y fue un dolor :

AwesomeClass hooray = null;
try {
  hooray = new AwesomeClass();
  // Great code
} finally {
  if (hooray!=null) {
    hooray.close();
  }
}

Y ese es solo el código cuando ni // Great codeni hooray.close()pueden lanzar excepciones.

Si realmente solo desea limitar el alcance de una variable, entonces un bloque de código simple hace el trabajo:

{
  AwesomeClass hooray = new AwesomeClass();
  // Great code
}

Pero probablemente eso no es lo que quisiste decir.

Joachim Sauer
fuente
1
Su equivalente de Java no debería ser un problema si // Great codelanza una excepción.
Cheeso
3
Cuando el constructor lanza una excepción, creo que su código dará como resultado una NullPointerException que enmascara la excepción original.
Michael Borgwardt
@Michael: en realidad, mi ejemplo no se compilaría, porque es horrayposible que no se haya inicializado en ese punto (arreglado ahora).
Joachim Sauer
4
+1 para bloques flotantes simples que pueden limitar el alcance. Sin embargo, cada vez que veo esto, casi siempre es un indicador de que el método debe dividirse en partes más pequeñas.
Mark Peters
1
si desea capturar alguna excepción del constructor, debe tenerla dentro del bloque try. Sería engorroso envolver todo en otro intento / captura.
THS
8

Técnicamente:

DisposableObject d = null;
try {
    d = new DisposableObject(); 
}
finally {
    if (d != null) {
        d.Dispose();
    }
}
ChaosPandion
fuente
2
No es la mejor forma de hacerlo. stackoverflow.com/questions/1909662/…
Mark Byers
5
Esto sería esencialmente equivalente. No me importa si es la mejor forma.
ChaosPandion
2
Escrito como un verdadero programador de C #. ;)
Neil
8

El equivalente java más cercano es

AwesomeClass hooray = new AwesomeClass();
try{
    // Great code
} finally {
    hooray.dispose(); // or .close(), etc.
}
Michael Borgwardt
fuente
3

A partir de ahora, no.

Sin embargo existe una propuesta de ARM para Java 7.

desaparecido faktor
fuente
2

Si está interesado en la gestión de recursos, Project Lombok ofrece la @Cleanupanotación. Tomado directamente de su sitio:

Puede usar @Cleanuppara asegurarse de que un recurso determinado se limpie automáticamente antes de que la ruta de ejecución del código salga de su alcance actual. Haz esto anotando cualquier declaración de variable local con la @Cleanup anotación así:

@Cleanup InputStream in = new FileInputStream("some/file");

Como resultado, al final del alcance en el que se encuentra, in.close()se llama. Se garantiza que esta llamada se ejecutará mediante una construcción try / finalmente. Mire el ejemplo a continuación para ver cómo funciona.

Si el tipo de objeto que le gustaría limpiar no tiene un close() método, pero algún otro método sin argumentos, puede especificar el nombre de este método así:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

De forma predeterminada, se supone que el método de limpieza es close(). Un método de limpieza que toma argumentos no se puede llamar a través de @Cleanup.

Vainilla Java

import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        out.close();
      }
    } finally {
      in.close();
    }
  }
}

Con Lombok

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}
Adam Paynter
fuente
1

Consulte esta lista de palabras clave de Java .

  1. La usingpalabra clave no es, por desgracia parte de la lista.
  2. Y tampoco hay equivalencia de la usingpalabra clave C # a través de cualquier otra palabra clave como por ahora en Java.

Para imitar tal "using"comportamiento, tendrá que usar un try...catch...finallybloque, donde dispondrá de los recursos dentro finally.

Will Marcouiller
fuente
6
El hecho de que usingno sea una palabra clave no significa nada. La misma función se puede implementar (¡y se implementará!) Con otra palabra clave, como mencionó @BalusC.
Joachim Sauer
1
¡Estoy de acuerdo! Pero por ahora, no existe, ¿verdad? Eso es lo que preguntó el OP, si había algo parecido en este momento. Es bueno saber que existirá en futuras versiones, pero eso no cambia nada por ahora, de una forma u otra. De todos modos, ¡la información proporcionada por @BalusC es genial! =)
Will Marcouiller
2
Estoy de acuerdo con eso, pero su publicación parece decir que el hecho de que usingno esté en la lista de palabras clave de Java significa que esta característica no está presente en el lenguaje Java. Y eso no es cierto.
Joachim Sauer
Si esto es lo que parece decir mi publicación, lo editaré para reflejar mi intención.
Will Marcouiller
Edité mi respuesta especificando que no había ninguna usingpalabra clave ni ninguna equivalencia como por ahora. ¡Gracias @Joachim Sauer! =)
Will Marcouiller
1

Los bloques ARM , del proyecto Coin , estarán en Java 7. Esta característica está destinada a brindar una funcionalidad similar a Java como .Net usando sintaxis.

krock
fuente
0

Responder a la pregunta sobre la limitación del alcance de una variable, en lugar de hablar de cerrar / eliminar automáticamente las variables.

En Java, puede definir ámbitos cerrados y anónimos utilizando llaves. Es extremadamente simple.

{
   AwesomeClass hooray = new AwesomeClass()
   // Great code
}

La variable hooraysolo está disponible en este ámbito y no fuera de él.

Esto puede ser útil si tiene variables repetidas que son solo temporales.

Por ejemplo, cada uno con index. Al igual que la itemvariable se cierra en el ciclo for (es decir, solo está disponible dentro de él), la indexvariable se cierra en el ámbito anónimo.

// first loop
{
    Integer index = -1;
    for (Object item : things) {index += 1;
        // ... item, index
    }
}

// second loop
{
    Integer index = -1;
    for (Object item : stuff) {index += 1;
        // ... item, index
    }
}

También utilizo esto a veces si no tiene un bucle for para proporcionar el alcance de la variable, pero desea usar nombres de variable genéricos.

{
    User user = new User();
    user.setId(0);
    user.setName("Andy Green");
    user.setEmail("[email protected]");
    users.add(user);
}

{
    User user = new User();
    user.setId(1);
    user.setName("Rachel Blue");
    user.setEmail("[email protected]");
    users.add(user);
}
Alex
fuente