Java a-t-il une instruction using?

107

Java a-t-il une instruction using qui peut être utilisée lors de l'ouverture d'une session en veille prolongée?

En C #, c'est quelque chose comme:

using (var session = new Session())
{


}

Ainsi, l'objet sort de sa portée et se ferme automatiquement.

mrblah
la source
4
"permettant de définir une portée pour un objet" Ce n'est pas ce que usingfait. La portée n'est pas à vie (et usingne concerne pas non plus la durée de vie, à proprement parler, car Disposene détruit pas la mémoire d'un objet.)
Joren
4
@Joren Votre commentaire est en train d'être voté mais je pourrais le faire avec un peu plus d'informations. C'est vous qui introduisez l'idée «à vie», alors vous dites qu'il ne s'agit pas de «vie». Scope est le terme utilisé dans la définition de la bibliothèque msdn, peut-être que je l'ai mal utilisé. Comment définiriez-vous le using statement.
Jla
1
La portée fait référence à la zone du code dans laquelle vous pouvez faire référence à un identifiant sans utiliser son nom complet (variable locale, type, nom de méthode, etc.). La durée de vie fait référence au temps pendant lequel un objet ou une variable est accessible. Voir blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren
2
Ainsi, par exemple, si vous avez une variable locale et que vous lui assignez une instance de type valeur, la durée de vie de votre valeur se terminera lorsque la durée de vie de sa variable se terminera. Mais si vous allouez un objet et stockez une référence à celui-ci dans un local, alors la durée de vie de cet objet peut très bien s'étendre au-delà de la durée de vie de son stockage, tant qu'il y a encore une référence à l'objet ailleurs. En ce qui concerne using, automatiquement dispose l'objet à la fin de son champ d' application, mais il n'a pas liberer l'objet - sa durée de vie est pas terminée jusqu'à ce que toutes ses références ont disparu.
Joren
1
duplication possible du mot-clé "using" en java
HaveNoDisplayName

Réponses:

124

Java 7 a introduit la gestion automatique des blocs de ressources qui apporte cette fonctionnalité à la plate-forme Java. Les versions précédentes de Java n'avaient rien de semblable using.

À titre d'exemple, vous pouvez utiliser n'importe quelle variable implémentée java.lang.AutoCloseablede la manière suivante:

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

L' java.io.Closeableinterface de Java , implémentée par des flux, s'étend automatiquement AutoCloseable, de sorte que vous pouvez déjà utiliser les flux dans un trybloc de la même manière que vous les utiliseriez dans un usingbloc C # . Ceci est équivalent à C #using .

Depuis la version 5.0, les sessions Hibernate sont implémentéesAutoCloseable et peuvent être fermées automatiquement dans les blocs ARM. Dans les versions précédentes de Hibernate Session ne mettait pas en œuvreAutoCloseable . Vous devrez donc être sur Hibernate> = 5.0 pour utiliser cette fonctionnalité.

Asaph
la source
1
"Heureusement" avec Java 7 étant disponible maintenant, cette réponse n'est plus vraie (et je pense que les blocs ARM sont exactement ce que usingfait).
Joachim Sauer
@Joachim Sauer: Merci. J'ai mis à jour ma réponse pour refléter le passage du temps. À votre point de vue, les blocs ARM sont exactement ce que fait l'utilisation; au moment où j'ai écrit cette réponse, il me semblait que les blocs ARM devaient être des blocs d'essai, alors que l'utilisation peut être appliquée à n'importe quel bloc arbitraire. En regardant maintenant, il semble que le mot clé do puisse être utilisé en java pour accomplir cela. Cela a-t-il été ajouté à la proposition récemment ou est-ce que je l'ai manqué la première fois? Le PO a également posé des questions spécifiques sur les sessions Hibernate. AFAIK: Les sessions Hibernate ne sont toujours pas implémentées AutoCloseableet ne peuvent donc pas encore utiliser ARM.
Asaph
1
Pas d'événement dans 4.3 Hibernate N'implémente PAS AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/ ... Je suppose que c'est à chacun d'écrire son propre wrapper?
Andrei Rînea
1
Session ne peut pas implémenter AutoCloseable car Session.close () renvoie une connexion. Je pense que c'est une mauvaise conception mais je doute que cela changera jamais.
usr-local-ΕΨΗΕΛΩΝ
@ usr-local-ΕΨΗΕΛΩΝ Je viens de me dire qu'ils obligeraient quiconque utilisant la mise en veille prolongée à passer à java 7 s'ils implémentaient cette interface. AutoCloseablen'existait pas avant java 7 l'a-t-il fait?
Neil
31

Avant Java 7 , une telle fonctionnalité n'existait pas en Java (pour Java 7 et plus, voir la réponse d' Asaph concernant ARM ).

Vous deviez le faire manuellement et c'était pénible :

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

Et c'est juste le code quand ni // Great codenihooray.close() ne peut lever d'exceptions.

Si vous voulez vraiment limiter la portée d'une variable, un simple bloc de code fait le travail:

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

Mais ce n'est probablement pas ce que vous vouliez dire.

Joachim Sauer
la source
1
Votre équivalent Java ne devrait poser aucun problème s'il // Great codelève une exception.
Cheeso
3
Lorsque le constructeur lève une exception, je pense que votre code va entraîner une NullPointerException qui masque l'exception d'origine.
Michael Borgwardt
@Michael: en fait, mon exemple ne serait pas compilé, car il se horraypeut qu'il n'ait pas été initialisé à ce stade (corrigé maintenant).
Joachim Sauer
4
+1 pour les blocs simples flottants pouvant limiter la portée. Cependant, chaque fois que je vois cela, c'est presque toujours un indicateur que la méthode doit être divisée en plus petits morceaux.
Mark Peters
1
si vous voulez attraper une exception du constructeur, vous devez l'avoir dans le bloc try. il serait fastidieux d'envelopper le tout dans un autre try / catch.
ths
8

Techniquement:

DisposableObject d = null;
try {
    d = new DisposableObject(); 
}
finally {
    if (d != null) {
        d.Dispose();
    }
}
ChaosPandion
la source
2
Pas la meilleure façon de le faire. stackoverflow.com/questions/1909662/…
Mark Byers
5
Ce serait essentiellement équivalent. Je m'en fiche si c'est la meilleure façon.
ChaosPandion
2
Écrit comme un vrai programmeur C #. ;)
Neil
8

L'équivalent java le plus proche est

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

A partir de maintenant, non.

Cependant, il existe une proposition d' ARM pour Java 7.

manquant
la source
2

Si vous êtes intéressé par la gestion des ressources, Project Lombok propose l' @Cleanupannotation. Tiré directement de leur site:

Vous pouvez utiliser @Cleanuppour vous assurer qu'une ressource donnée est automatiquement nettoyée avant que le chemin d'exécution du code ne quitte votre étendue actuelle. Pour ce faire, annotez toute déclaration de variable locale avec l' @Cleanup annotation comme suit:

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

En conséquence, à la fin de la portée dans laquelle vous vous trouvez, in.close() est appelée. Cet appel est garanti de s'exécuter par le biais d'une construction try / finally. Regardez l'exemple ci-dessous pour voir comment cela fonctionne.

Si le type d'objet que vous souhaitez nettoyer n'a pas de close() méthode, mais une autre méthode sans argument, vous pouvez spécifier le nom de cette méthode comme suit:

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

Par défaut, la méthode de nettoyage est présumée être close(). Une méthode de nettoyage qui prend un argument ne peut pas être appelée via @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();
    }
  }
}

Avec 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
la source
1

Veuillez consulter cette liste de mots-clés Java .

  1. Le usingmot-clé ne fait malheureusement pas partie de la liste.
  2. Et il n'y a pas non plus d'équivalence du usingmot-clé C # avec un autre mot-clé comme pour l'instant en Java.

Pour imiter un tel "using"comportement, vous devrez utiliser un try...catch...finallybloc dans lequel vous disposerez des ressources qu'il contient finally.

Will Marcouiller
la source
6
Le fait que ce usingne soit pas un mot-clé ne veut rien dire. La même fonctionnalité peut être (et sera!) Implémentée avec un autre mot-clé, comme @BalusC l'a mentionné.
Joachim Sauer
1
Je suis d'accord! Mais pour l'instant, ça n'existe pas, non? C'est ce que le PO a demandé, s'il y avait quelque chose de semblable à l'instant. Il est bon de savoir qu'il existera dans les prochaines versions, mais cela ne change rien pour le moment, d'une manière ou d'une autre. Quoi qu'il en soit, les informations fournies par @BalusC sont excellentes! =)
Will Marcouiller
2
Je suis d'accord avec cela, mais votre message semble dire que le fait que ce usingne soit pas dans la liste des mots-clés Java signifie que cette fonctionnalité n'est pas présente dans le langage Java. Et ce n'est pas vrai.
Joachim Sauer
Si c'est ce que mon message semble dire, je le modifierai pour refléter mon intention.
Will Marcouiller
J'ai édité ma réponse en précisant qu'il n'y avait aucun usingmot-clé, ni aucune équivalence comme pour l'instant. Merci @Joachim Sauer! =)
Will Marcouiller
1

Les blocs ARM , de la pièce du projet, seront en Java 7. Cette fonctionnalité est destinée à apporter à Java des fonctionnalités similaires à celles du .Net en utilisant la syntaxe.

Krock
la source
0

Pour répondre à la question concernant la limitation de la portée d'une variable, au lieu de parler de la fermeture / suppression automatique des variables.

En Java, vous pouvez définir des étendues fermées et anonymes en utilisant des accolades. C'est extrêmement simple.

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

La variable hoorayn'est disponible que dans cette étendue, et non en dehors.

Cela peut être utile si vous avez des variables répétitives qui ne sont que temporaires.

Par exemple, chacun avec index. Tout comme la itemvariable est fermée sur la boucle for (c'est-à-dire qu'elle n'est disponible qu'à l'intérieur), la indexvariable est fermée sur la portée anonyme.

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

J'utilise également cela parfois si vous n'avez pas de boucle for pour fournir une portée de variable, mais que vous souhaitez utiliser des noms de variables génériques.

{
    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);
}
Alex
la source