Java ha un'istruzione using?


107

Java ha un'istruzione using che può essere utilizzata quando si apre una sessione in ibernazione?

In C # è qualcosa del tipo:

using (var session = new Session())
{


}

Quindi l'oggetto esce dall'ambito e si chiude automaticamente.


4
"che consente di definire un ambito per un oggetto" Questo non è ciò che usingfa. L'ambito non è la vita (e usingnon riguarda nemmeno la vita, in senso stretto, poiché Disposenon distrugge la memoria di un oggetto).
Joren

4
@Joren Il tuo commento viene votato in alto ma potrei fare con un po 'più di informazioni. Tu sei quello che introduce l'idea della "vita" e poi dici che non si tratta della "vita". Scope è il termine usato nella definizione dalla libreria msdn, forse l'ho usato impropriamente. Come definiresti il ​​file using statement.
Jla

1
L'ambito si riferisce all'area nel codice in cui è possibile fare riferimento a un identificatore senza utilizzare il suo nome completo (variabile locale, tipo, nome del metodo e così via). La durata si riferisce al tempo in cui un oggetto o una variabile è accessibile. Vedi blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren

2
Quindi, ad esempio, se hai una variabile locale e le assegni un'istanza del tipo di valore, la durata del tuo valore terminerà quando la durata della sua variabile termina. Ma se hai allocato un oggetto e memorizzato un riferimento ad esso in un locale, la durata di quell'oggetto potrebbe estendersi ben oltre la durata della sua memorizzazione, purché vi sia ancora qualche riferimento all'oggetto altrove. Per quanto riguarda using, dispone automaticamente l'oggetto alla fine del suo ambito, ma non dealloca l'oggetto: la sua durata non termina finché tutti i suoi riferimenti non sono scomparsi.
Joren

1
possibile duplicato della parola chiave "using" in java
HaveNoDisplayName

Risposte:


124

Java 7 ha introdotto la gestione automatica dei blocchi delle risorse che porta questa funzionalità sulla piattaforma Java. Le versioni precedenti di Java non avevano nulla di simile using.

Ad esempio, puoi utilizzare qualsiasi variabile implementata java.lang.AutoCloseablenel modo seguente:

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

L' java.io.Closeableinterfaccia di Java , implementata dagli stream, si estende automaticamente AutoCloseable, quindi puoi già utilizzare gli stream in un filetry blocco nello stesso modo in cui li useresti in un usingblocco C # . Questo è equivalente a C #using .

A partire dalla versione 5.0, Hibernate Sessions implementaAutoCloseable e può essere chiuso automaticamente in blocchi ARM. Nelle versioni precedenti di Hibernate Session non era implementatoAutoCloseable . Quindi dovrai essere su Hibernate> = 5.0 per utilizzare questa funzione.


1
"Fortunatamente" con Java 7 ora disponibile, questa risposta non è più vera (e penso che i blocchi ARM siano esattamente ciò che usingfa).
Joachim Sauer

@Joachim Sauer: Grazie. Ho aggiornato la mia risposta per riflettere il passare del tempo. Al punto che i blocchi ARM sono esattamente ciò che fa l'uso; al momento in cui ho scritto questa risposta, mi sembrava che i blocchi ARM dovessero essere blocchi di prova, mentre l'utilizzo può essere applicato a qualsiasi blocco arbitrario. Guardandola ora, sembra che la parola chiave do possa essere utilizzata in java per ottenere ciò. È stato aggiunto alla proposta di recente o l'ho perso la prima volta? Anche l'OP ha chiesto specificamente delle sessioni di ibernazione. AFAIK: Le sessioni di ibernazione non vengono ancora implementate, AutoCloseablequindi non possono ancora utilizzare ARM.
Asaph il

1
Nessun evento in 4.3 Hibernate NON implementa AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Immagino che spetti a tutti scrivere il proprio wrapper?
Andrei Rînea

1
La sessione non può implementare AutoCloseable poiché Session.close () restituisce una connessione. Penso che questo sia un cattivo design, ma dubito che sarà mai cambiato.
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝ Ho appena pensato che avrebbero obbligato chiunque usasse hibernate a passare a java 7 se avessero implementato quell'interfaccia. AutoCloseablenon esisteva prima di Java 7 vero?
Neil

31

Prima di Java 7 , non esisteva tale funzionalità in Java (per Java 7 e versioni successive vedere la risposta di Asaph riguardo ARM ).

Dovevi farlo manualmente ed è stato un dolore :

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

E questo è solo il codice quando né // Great codehooray.close()può generare eccezioni.

Se vuoi davvero limitare solo l'ambito di una variabile, allora un semplice blocco di codice fa il lavoro:

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

Ma probabilmente non è quello che intendevi.


1
Il tuo equivalente Java non dovrebbe essere un problema se // Great codegenera un'eccezione.
Cheeso

3
Quando il costruttore lancia un'eccezione, penso che il tuo codice risulterà in una NullPointerException che maschera l'eccezione originale.
Michael Borgwardt

@ Michael: in realtà il mio esempio non si sarebbe compilato, perché horraypotrebbe non essere stato inizializzato a quel punto (risolto ora).
Joachim Sauer

4
+1 per blocchi semplici mobili che sono in grado di limitare l'ambito. Tuttavia, ogni volta che li vedo è quasi sempre un indicatore che il metodo dovrebbe essere suddiviso in blocchi più piccoli.
Mark Peters

1
se vuoi catturare un'eccezione dal costruttore, devi averla all'interno del blocco try. sarebbe complicato racchiudere il tutto in un altro tentativo / cattura.
giovedì



8

L'equivalente java più vicino è

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



2

Se sei interessato alla gestione delle risorse, Project Lombok offre l' @Cleanupannotazione. Tratto direttamente dal loro sito:

È possibile utilizzare @Cleanupper garantire che una determinata risorsa venga automaticamente ripulita prima che il percorso di esecuzione del codice esca dall'ambito corrente. Puoi farlo annotando qualsiasi dichiarazione di variabile locale con l' @Cleanup annotazione in questo modo:

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

Di conseguenza, alla fine dell'ambito in cui ti trovi, in.close()viene chiamato. Questa chiamata è garantita per essere eseguita tramite un costrutto try / infine. Guarda l'esempio qui sotto per vedere come funziona.

Se il tipo di oggetto che desideri pulire non ha un close() metodo, ma un altro metodo senza argomenti, puoi specificare il nome di questo metodo in questo modo:

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

Per impostazione predefinita, si presume che il metodo di pulizia sia close(). Un metodo di pulizia che accetta argomenti non può essere chiamato tramite @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();
    }
  }
}

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


1

Consulta questo elenco di parole chiave Java .

  1. La usingparola chiave purtroppo non fa parte dell'elenco.
  2. E non c'è nemmeno l'equivalenza della usingparola chiave C # attraverso qualsiasi altra parola chiave come per ora in Java.

Per imitare tale "using"comportamento, dovrai utilizzare un try...catch...finallyblocco, in cui smaltire le risorse all'interno finally.


6
Il fatto che usingnon sia una parola chiave non significa nulla. La stessa funzione può essere (e sarà!) Implementata con un'altra parola chiave, come menzionato da @BalusC.
Joachim Sauer

1
Sono d'accordo! Ma per ora non esiste, giusto? Questo è ciò che l'OP ha chiesto, se ci fosse qualcosa di simile proprio ora. È bello sapere che esisterà nelle versioni future, ma ciò non cambia nulla come per ora, in un modo o nell'altro. Comunque, le informazioni fornite da @BalusC sono comunque fantastiche! =)
Will Marcouiller

2
Sono d'accordo, ma il tuo post sembra dire che il fatto che usingnon sia nell'elenco delle parole chiave Java significa che questa funzionalità non è presente nel linguaggio Java. E non è vero.
Joachim Sauer

Se questo è ciò che sembra dire il mio post, lo modificherò per riflettere la mia intenzione.
Will Marcouiller

Ho modificato la mia risposta specificando che non c'erano usingparole chiave e nemmeno equivalenze come per ora. Grazie @Joachim Sauer! =)
Will Marcouiller


0

Per rispondere alla domanda riguardante la limitazione dell'ambito di una variabile, invece di parlare di chiusura / eliminazione automatica delle variabili.

In Java è possibile definire ambiti chiusi e anonimi utilizzando parentesi graffe. È estremamente semplice.

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

La variabile hoorayè disponibile solo in questo ambito e non al di fuori di esso.

Questo può essere utile se hai variabili ripetute che sono solo temporanee.

Ad esempio, ciascuno con index. Proprio come la itemvariabile è chiusa nel ciclo for (cioè è disponibile solo al suo interno), la indexvariabile è chiusa nello scope anonimo.

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

A volte lo uso anche se non si dispone di un ciclo for per fornire l'ambito delle variabili, ma si desidera utilizzare nomi di variabili generici.

{
    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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.