Czy Java ma instrukcję using?

108

Czy Java ma instrukcję using, której można użyć podczas otwierania sesji w stanie hibernacji?

W C # jest to coś takiego:

using (var session = new Session())
{


}

Więc obiekt wychodzi poza zasięg i zamyka się automatycznie.

mrblah
źródło
4
„pozwolenie na zdefiniowanie zakresu dla obiektu” To nie jest to, co usingrobi. Zakres nie jest życiem (i usingnie dotyczy też życia, ściśle mówiąc, ponieważ Disposenie niszczy pamięci obiektu.)
Joren
4
@Joren Twój komentarz jest coraz lepiej głosowany, ale przydałoby się trochę więcej informacji. To ty wprowadzasz ideę „życia”, a potem mówisz, że nie chodzi o „całe życie”. Zakres to termin użyty w definicji z biblioteki msdn, być może nadużyłem go. Jak zdefiniowałbyś using statement.
Jla
1
Zakres odnosi się do obszaru w kodzie, w którym można odwołać się do identyfikatora bez używania jego w pełni kwalifikowanej nazwy (zmienna lokalna, typ, nazwa metody itp.). Okres istnienia odnosi się do czasu, w którym obiekt lub zmienna jest dostępna. Zobacz blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren
2
Na przykład, jeśli masz zmienną lokalną i przypiszesz do niej wystąpienie typu wartości, to okres istnienia wartości zakończy się, gdy skończy się okres istnienia jej zmiennej. Ale jeśli przydzieliłeś obiekt i zapisałeś do niego odniesienie w lokalnym, to czas życia tego obiektu może bardzo dobrze przekroczyć czas jego przechowywania, o ile nadal istnieje odniesienie do obiektu w innym miejscu. Co do tego using, automatycznie usuwa obiekt na końcu jego zakresu, ale nie zwalnia obiektu - jego żywotność nie kończy się, dopóki wszystkie jego odniesienia nie znikną.
Joren
1
możliwy duplikat słowa kluczowego „using” w java
HaveNoDisplayName

Odpowiedzi:

125

Java 7 wprowadziła automatyczne zarządzanie blokami zasobów, które przenosi tę funkcję na platformę Java. Poprzednie wersje Javy nie miały nic podobnego using.

Jako przykład możesz użyć dowolnej zmiennej implementującej java.lang.AutoCloseablew następujący sposób:

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

java.io.CloseableInterfejs Java , zaimplementowany przez strumienie, automatycznie się rozszerza AutoCloseable, więc możesz już używać strumieni w trybloku w taki sam sposób, jak w usingbloku C # . Jest to odpowiednik C # using.

Począwszy od wersji 5.0, sesje hibernacji implementująAutoCloseable i mogą być automatycznie zamykane w blokach ARM. W poprzednich wersjach Hibernate Session nie zaimplementowanoAutoCloseable . Aby móc korzystać z tej funkcji, musisz być w trybie Hibernate> = 5.0.

Asaf
źródło
1
„Na szczęście”, ponieważ Java 7 jest już dostępna, ta odpowiedź nie jest już prawdą (i myślę, że bloki ARM są dokładnie tym , co usingrobi).
Joachim Sauer
@Joachim Sauer: Dzięki. Zaktualizowałem swoją odpowiedź, aby odzwierciedlić upływ czasu. Do twojego punktu, w którym bloki ARM są dokładnie tym, co robi użycie; w momencie, gdy pisałem tę odpowiedź, wydawało mi się, że bloki ARM muszą być blokami próbnymi, podczas gdy użycie można zastosować do dowolnego dowolnego bloku. Patrząc na to teraz, wydaje się, że słowo kluczowe do może być użyte w java, aby to osiągnąć. Czy to zostało dodane do propozycji niedawno, czy przegapiłem to za pierwszym razem? Również OP zapytał konkretnie o sesje hibernacji. AFAIK: Sesje hibernacji nadal nie są implementowane, AutoCloseablewięc nie mogą jeszcze używać ARM.
Asaph
1
Nie zdarzenie w 4.3 Hibernacja NIE implementuje AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Myślę, że każdy powinien napisać własny wrapper?
Andrei Rînea
1
Sesja nie może zaimplementować funkcji AutoCloseable, ponieważ Session.close () zwraca Connection. Myślę, że to zły projekt, ale wątpię, że kiedykolwiek zostanie to zmienione.
usr-local-ΕΨΗΕΛΩΝ
@ usr-local-ΕΨΗΕΛΩΝ Po prostu pomyślałem, że będą zobowiązać każdego, kto używa hibernacji, do przejścia na java 7, jeśli zaimplementują ten interfejs. AutoCloseablenie istniał przed Java 7, prawda?
Neil
31

Przed Java 7 , nie było żadnego z takich funkcji w Java (Java 7, a nawet zobaczyć Asafa odpowiedź „s dotyczącą ARM ).

Trzeba było to zrobić ręcznie i było to uciążliwe :

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

I to tylko kod, w którym ani // Great codeani nie hooray.close()mogą zgłaszać żadnych wyjątków.

Jeśli naprawdę chcesz ograniczyć zakres zmiennej, wystarczy prosty blok kodu:

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

Ale prawdopodobnie nie to miałeś na myśli.

Joachim Sauer
źródło
1
Twój odpowiednik w Javie nie powinien stanowić problemu, jeśli // Great codezgłosi wyjątek.
Cheeso
3
Kiedy konstruktor zgłosi wyjątek, myślę, że twój kod spowoduje wyjątek NullPointerException, który maskuje oryginalny wyjątek.
Michael Borgwardt
@Michael: w rzeczywistości mój przykład nie mógł się skompilować, ponieważ horraymógł nie zostać zainicjowany w tym momencie (teraz naprawiony).
Joachim Sauer
4
+1 za pływające proste bloki, które mogą ograniczać zasięg. Jednak gdy je widzę, prawie zawsze jest to wskazówką, że metoda powinna zostać podzielona na mniejsze części.
Mark Peters
1
jeśli chcesz wyłapać jakikolwiek wyjątek od konstruktora, musisz go umieścić w bloku try. zawinięcie całości w kolejną próbę / złapanie byłoby uciążliwe.
tys
8

Technicznie:

DisposableObject d = null;
try {
    d = new DisposableObject(); 
}
finally {
    if (d != null) {
        d.Dispose();
    }
}
ChaosPandion
źródło
2
Nie jest to najlepszy sposób na zrobienie tego. stackoverflow.com/questions/1909662/…
Mark Byers
5
Byłoby to zasadniczo równoważne. Nie obchodzi mnie, czy to najlepszy sposób.
ChaosPandion
2
Napisany jak prawdziwy programista C #. ;)
Neil
8

Najbliższy odpowiednik Java to

AwesomeClass hooray = new AwesomeClass();
try{
    // Great code
} finally {
    hooray.dispose(); // or .close(), etc.
}
Michael Borgwardt
źródło
3

Na razie nie.

Istnieje jednak propozycja ARM dla Java 7.

missingfaktor
źródło
2

Jeśli interesuje Cię zarządzanie zasobami, Project Lombok oferuje @Cleanupadnotację. Zrobione bezpośrednio z ich witryny:

Możesz użyć, @Cleanupaby upewnić się, że dany zasób jest automatycznie czyszczony, zanim ścieżka wykonywania kodu opuści bieżący zakres. Robisz to, dodając adnotacje do dowolnej deklaracji zmiennej lokalnej z @Cleanup adnotacją w następujący sposób:

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

W rezultacie na końcu zakresu, w którym się in.close()znajdujesz, nazywa się. Gwarantujemy, że to wywołanie zostanie uruchomione za pomocą konstrukcji try / final. Spójrz na poniższy przykład, aby zobaczyć, jak to działa.

Jeśli typ obiektu, który chcesz wyczyścić, nie ma close() metody, ale inną metodę bezargumentową, możesz określić nazwę tej metody w następujący sposób:

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

Domyślnie przyjmuje się, że metoda czyszczenia to close(). Metoda czyszczenia, która przyjmuje argument, nie może zostać wywołana przez @Cleanup.

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

Z 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
źródło
1

Zobacz tę listę słów kluczowych Java .

  1. To usingsłowo kluczowe niestety nie jest częścią listy.
  2. Nie ma też odpowiednika usingsłowa kluczowego C # z jakimkolwiek innym słowem kluczowym, jak na razie w Javie.

Aby naśladować takie "using"zachowanie, będziesz musiał użyć try...catch...finallybloku, w którym pozbyłeś się zasobów finally.

Will Marcouiller
źródło
6
Fakt, że usingnie jest to słowo kluczowe, nic nie znaczy. Ta sama funkcja może być (i będzie!) Zaimplementowana za pomocą innego słowa kluczowego, jak wspomniano w @BalusC.
Joachim Sauer
1
Zgadzam się! Ale na razie nie istnieje, prawda? Właśnie o to zapytał PO, jeśli przed chwilą było coś podobnego. Dobrze jest wiedzieć, że będzie istniał w przyszłych wydaniach, ale na razie to niczego nie zmienia, w taki czy inny sposób. W każdym razie informacje podane przez @BalusC są świetne! =)
Will Marcouiller
2
Zgadzam się z tym, ale Twój post wydaje się mówić, że fakt, że usingnie ma go na liście słów kluczowych Java, oznacza, że ​​ta funkcja nie jest obecna w języku Java. To nieprawda.
Joachim Sauer
Jeśli tak wydaje się mówić mój post, edytuję, aby odzwierciedlić moje zamiary.
Will Marcouiller
Zredagowałem swoją odpowiedź, podając, że nie ma usingsłowa kluczowego i na razie nie ma odpowiednika. Dzięki @Joachim Sauer! =)
Will Marcouiller
0

Aby odpowiedzieć na pytanie dotyczące ograniczania zakresu zmiennej, zamiast mówić o automatycznym zamykaniu / usuwaniu zmiennych.

W Javie można definiować zamknięte, anonimowe zakresy za pomocą nawiasów klamrowych. To niezwykle proste.

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

Zmienna hoorayjest dostępna tylko w tym zakresie, a nie poza nim.

Może to być przydatne, jeśli masz powtarzające się zmienne, które są tylko tymczasowe.

Na przykład każdy z index. Tak jak itemzmienna jest zamykana w pętli for (tj. Jest dostępna tylko w niej), tak indexzmienna jest zamykana w zakresie anonimowym.

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

Używam tego również czasami, jeśli nie masz pętli for, aby zapewnić zakres zmiennych, ale chcesz używać ogólnych nazw zmiennych.

{
    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
źródło