Hat Java eine using-Anweisung?


106

Verfügt Java über eine using-Anweisung, die beim Öffnen einer Sitzung im Ruhezustand verwendet werden kann?

In C # ist es so etwas wie:

using (var session = new Session())
{


}

Das Objekt verlässt also den Gültigkeitsbereich und wird automatisch geschlossen.


4
"Erlauben, einen Bereich für ein Objekt zu definieren" Das ist nicht was using. Der Umfang ist nicht lebenslang (und usingstreng genommen auch nicht lebenslang, da er Disposedas Gedächtnis eines Objekts nicht zerstört.)
Joren

4
@Joren Dein Kommentar wird hochgestimmt, aber ich könnte ein bisschen mehr Infos gebrauchen. Du bist derjenige, der die Idee "Leben" einführt, dann sagst du, es geht nicht um "Leben". Scope ist der Begriff, der in der Definition aus der msdn-Bibliothek verwendet wird. Vielleicht habe ich ihn missbraucht. Wie würden Sie die definieren using statement.
Jla

1
Der Bereich bezieht sich auf den Bereich im Code, in dem Sie auf einen Bezeichner verweisen können, ohne dessen vollständig qualifizierten Namen (lokale Variable, Typ, Methodenname usw.) zu verwenden. Die Lebensdauer bezieht sich auf die Zeit, in der auf ein Objekt oder eine Variable zugegriffen werden kann. Siehe blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren

2
Wenn Sie beispielsweise eine lokale Variable haben und ihr eine Werttypinstanz zuweisen, endet die Lebensdauer Ihres Werts, wenn die Lebensdauer der Variablen endet. Wenn Sie jedoch ein Objekt zugewiesen und einen Verweis darauf in einem lokalen Objekt gespeichert haben, kann die Lebensdauer dieses Objekts durchaus über die Lebensdauer seines Speichers hinausgehen, solange an anderer Stelle noch ein Verweis auf das Objekt vorhanden ist. Was usinges automatisch verfügt das Objekt am Ende ihres Umfangs, aber nicht freigeben das Objekt - seine Lebenszeit nicht zu Ende ist , bis alle seine Referenzen sind verschwunden.
Joren

Antworten:


123

Java 7 führte die automatische Ressourcenblockverwaltung ein, die diese Funktion auf die Java-Plattform bringt. Frühere Versionen von Java hatten nichts Ähnliches using.

Als Beispiel können Sie jede Variable verwenden, java.lang.AutoCloseabledie folgendermaßen implementiert wird:

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

Die java.io.Closeablevon Streams implementierte Java- Schnittstelle wird automatisch erweitert AutoCloseable, sodass Sie Streams in einem tryBlock bereits so verwenden können, wie Sie sie in einem C # using-Block verwenden würden. Dies entspricht C # using.

Ab Version 5.0 werden Hibernate Sessions implementiertAutoCloseable und können in ARM-Blöcken automatisch geschlossen werden. In früheren Versionen von Hibernate Session wurde nicht implementiertAutoCloseable . Sie müssen sich also im Ruhezustand> = 5.0 befinden, um diese Funktion nutzen zu können.


1
"Zum Glück", da Java 7 jetzt verfügbar ist, ist diese Antwort nicht mehr wahr (und ich denke, dass ARM-Blöcke genau das sind, was sie usingtun).
Joachim Sauer

@ Joachim Sauer: Danke. Ich habe meine Antwort aktualisiert, um den Lauf der Zeit widerzuspiegeln. Bis zu dem Punkt, dass ARM-Blöcke genau das sind, was die Verwendung bewirkt; Als ich diese Antwort schrieb, sah es für mich so aus, als müssten ARM-Blöcke Try-Blöcke sein, während die Verwendung auf jeden beliebigen Block angewendet werden kann. Wenn man es jetzt betrachtet, scheint es, als ob das Schlüsselwort do in Java verwendet werden kann, um dies zu erreichen. Wurde das kürzlich dem Vorschlag hinzugefügt oder habe ich es das erste Mal verpasst? Auch das OP fragte speziell nach Hibernate Sessions. AFAIK: Hibernate Sessions werden immer noch nicht implementiert, AutoCloseablesodass sie ARM noch nicht verwenden können.
Asaph

1
Kein Ereignis in 4.3 Ruhezustand Implementiert NICHT AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Ich denke, es liegt an jedem, seinen eigenen Wrapper zu schreiben?
Andrei Rînea

1
Die Sitzung kann AutoCloseable nicht implementieren, da Session.close () eine Verbindung zurückgibt. Ich denke, das ist ein schlechtes Design, aber ich bezweifle, dass dies jemals geändert wird.
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝ Ich dachte nur, dass sie jeden, der den Ruhezustand verwendet, dazu verpflichten würden, auf Java 7 umzuschalten, wenn sie diese Schnittstelle implementieren würden. AutoCloseableexistierte nicht vor Java 7, oder?
Neil

31

Vor Java 7 gab es in Java keine solche Funktion (für Java 7 und höher siehe Asaphs Antwort zu ARM ).

Sie mussten es manuell tun und es war ein Schmerz :

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

Und das ist nur der Code, wenn weder // Great codenoch hooray.close()Ausnahmen ausgelöst werden können.

Wenn Sie wirklich nur den Umfang einer Variablen einschränken möchten, erledigt ein einfacher Codeblock die Aufgabe:

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

Aber das haben Sie wahrscheinlich nicht gemeint.


1
Ihr Java-Äquivalent sollte kein Problem sein, wenn // Great codeeine Ausnahme ausgelöst wird.
Cheeso

3
Wenn der Konstruktor eine Ausnahme auslöst, wird Ihr Code wahrscheinlich zu einer NullPointerException führen, die die ursprüngliche Ausnahme maskiert.
Michael Borgwardt

@Michael: Eigentlich würde mein Beispiel nicht kompiliert werden, da horrayes zu diesem Zeitpunkt möglicherweise nicht initialisiert wurde (jetzt behoben).
Joachim Sauer

4
+1 für schwebende einfache Blöcke, die den Umfang einschränken können. Wenn ich diese sehe, ist dies jedoch fast immer ein Indikator dafür, dass die Methode in kleinere Teile aufgeteilt werden sollte.
Mark Peters

1
Wenn Sie eine Ausnahme vom Konstruktor abfangen möchten, müssen Sie sie im try-Block haben. Es wäre umständlich, das Ganze in einen anderen Versuch / Fang zu verpacken.
25.



8

Das nächste Java-Äquivalent ist

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



2

Wenn Sie sich für Ressourcenmanagement interessieren, bietet Project Lombok die @CleanupAnmerkung an. Direkt von ihrer Website genommen:

Sie können @Cleanupdamit sicherstellen, dass eine bestimmte Ressource automatisch bereinigt wird, bevor der Codeausführungspfad Ihren aktuellen Bereich verlässt. Sie tun dies, indem Sie eine lokale Variablendeklaration mit der folgenden @Cleanup Annotation versehen:

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

Am Ende des Bereichs, in dem Sie sich befinden, in.close() aufgerufen. Dieser Aufruf wird garantiert über ein try / finally-Konstrukt ausgeführt. Sehen Sie sich das folgende Beispiel an, um zu sehen, wie dies funktioniert.

Wenn der Objekttyp, den Sie bereinigen möchten, keine close() Methode, sondern eine andere Methode ohne Argumente enthält, können Sie den Namen dieser Methode wie folgt angeben:

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

Standardmäßig wird die Bereinigungsmethode angenommen close(). Eine Bereinigungsmethode, die Argumente akzeptiert, kann nicht über aufgerufen werden @Cleanup.

Vanille 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();
    }
  }
}

Mit 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);
    }
  }
}


1

Bitte beachten Sie diese Liste der Java-Schlüsselwörter .

  1. Das usingSchlüsselwort ist leider nicht Teil der Liste.
  2. Und es gibt auch keine Äquivalenz des C # using-Schlüsselworts durch ein anderes Schlüsselwort wie derzeit in Java.

Um ein solches "using"Verhalten nachzuahmen , müssen Sie einen try...catch...finallyBlock verwenden, in dem Sie die darin enthaltenen Ressourcen entsorgen würden finally.


6
Die Tatsache, dass usinges sich nicht um ein Schlüsselwort handelt, bedeutet nichts. Dieselbe Funktion kann (und wird!) Mit einem anderen Schlüsselwort implementiert werden, wie @BalusC erwähnt.
Joachim Sauer

1
Genau! Aber im Moment existiert es nicht, oder? Das hat das OP gefragt, ob es gerade etwas Ähnliches gibt. Es ist gut zu wissen, dass es in zukünftigen Versionen existieren wird, aber das ändert nichts an dem Moment, auf die eine oder andere Weise. Trotzdem sind die Informationen von @BalusC großartig! =)
Will Marcouiller

2
Ich stimme dem zu, aber Ihr Beitrag scheint zu sagen, dass die Tatsache, dass usingnicht in der Liste der Java-Schlüsselwörter enthalten ist, bedeutet, dass diese Funktion in der Java-Sprache nicht vorhanden ist. Und das stimmt nicht.
Joachim Sauer

Wenn dies in meinem Beitrag zu sagen scheint, werde ich es bearbeiten, um meine Absicht widerzuspiegeln.
Will Marcouiller

Ich habe meine Antwort so bearbeitet, dass es kein usingSchlüsselwort und auch keine Äquivalenz gibt. Danke @Joachim Sauer! =)
Will Marcouiller


0

Beantwortung der Frage zur Einschränkung des Gültigkeitsbereichs einer Variablen, anstatt über das automatische Schließen / Entsorgen von Variablen zu sprechen.

In Java können Sie geschlossene, anonyme Bereiche in geschweiften Klammern definieren. Es ist sehr einfach.

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

Die Variable hoorayist nur in diesem Bereich verfügbar und nicht außerhalb.

Dies kann nützlich sein, wenn Sie sich wiederholende Variablen haben, die nur vorübergehend sind.

Zum Beispiel jeweils mit Index. So wie die itemVariable über die for-Schleife geschlossen wird (dh nur innerhalb dieser Schleife verfügbar ist), wird die indexVariable über den anonymen Bereich geschlossen.

// 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
    }
}

Ich verwende dies manchmal auch, wenn Sie keine for-Schleife haben, um den Variablenbereich bereitzustellen, aber generische Variablennamen verwenden möchten.

{
    User user = new User();
    user.setId(0);
    user.setName("Andy Green");
    user.setEmail("andygreen@gmail.com");
    users.add(user);
}

{
    User user = new User();
    user.setId(1);
    user.setName("Rachel Blue");
    user.setEmail("rachelblue@gmail.com");
    users.add(user);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.