web-dev-qa-db-fra.com

Pourquoi l'essai avec ressource nécessite-t-il une variable locale?

En référence à ma question Tout risque dans un wrapper à fermeture automatique pour Java.util.concurrent.locks.Lock? , je me demande pourquoi trh try-with-resource nécessite une variable locale nommée .

Mon utilisation actuelle est la suivante:

try (AutoCloseableReentrantReadWiteLock.Lock l = _lock.writeLock()) {
    // do something
}        

La variable l n'est pas utilisée dans le bloc try et ne pollue que l'espace de noms. D'après ce que je me souviens de l'analogue C#using, l'instruction ne nécessite pas de variable nommée locale.

Y a-t-il une raison pour laquelle les éléments suivants n'ont pas pu être pris en charge, avec une variable locale anonyme qui est fermée à la fin du bloc try?

try (_lock.writeLock()) {
    // do something
}        
59

Le lien dans le commentaire de @McDowell révèle la bonne réponse dans n commentaire de blog par Joe Darcy qui a dirigé le Java Technology Specification that a introduit l'instruction try-with-resources:

De retour dans JDK 7, nous avons commencé avec une construction d'essayer avec des ressources comme celle-ci qui permettait d'utiliser une expression générale pour la ressource, y compris un appel de méthode. Cependant, le groupe d'experts a constaté par le premier projet de révision ( http://jcp.org/aboutJava/communityprocess/edr/jsr334/index.html ) que

"Un éventuel changement futur [à l'état d'essai avec les ressources] supprime la prise en charge d'une ressource à spécifier en tant qu'expression générale. Les spécificités non triviales et les complexités d'implémentation découlent du fait d'autoriser une expression générale à être utilisée comme ressource. Une expression restreinte qui pourrait être un identifiant ou un PrimaryNoNewArray peut suffire. Même la restriction la plus sévère de simplement autoriser un identifiant peut fournir presque toute l'utilité supplémentaire d'autoriser une expression complète (forcer la déclaration d'une nouvelle variable de ressource) à une implémentation marginale beaucoup plus faible et impact des spécifications. "

À la fin de JDK 7, nous voulions une nouvelle déclaration de variable pour la ressource ou une variable finale finale/effectivement existante. Nous n'avons eu le temps de fournir le premier qu'en 7; en 9, nous fournissons ce dernier aussi.

13
Zero3

Parmi les cas d'utilisation qu'ils envisageaient, la plupart auraient besoin d'accéder à la ressource à l'intérieur du bloc, par exemple, ouvrir un fichier - lire/écrire un fichier - fermer un fichier. Ils n'auraient pas pris cette décision de conception s'ils avaient pensé qu'il existe de nombreux cas d'utilisation où la variable locale n'est pas utilisée.

Quant à savoir pourquoi Lock n'est pas auto-fermable, je pense que Doug Lea n'est pas trop préoccupé par la question de la syntaxe, il se concentre sur la résolution du problème difficile. D'autres peuvent toujours ajouter du sucre de syntaxe en plus de ses utilitaires.

À l'avenir, l'essayage avec les ressources va probablement devenir démodé, remplacé par lambda. Par exemple

lock.withLock( ()->{ execute-while-holding-the-lock; } );
8
ZhongYu

Autant que j'aurais souhaité que ce ne soit pas le cas, la justification sous-jacente est que l'essai avec des ressources est strictement destiné aux opérations sur l'article qui doit être éliminé. Il nécessite une variable nommée car il s'attend à ce que vous fassiez quelque chose avec cette variable pendant que vous êtes à l'intérieur du bloc. Je suppose que c'est comme si le compilateur disait "Si vous ne prévoyez pas réellement d'utiliser la ressource, pourquoi faites-vous un essai avec les ressources?"

Maintenant, vous et moi savons très bien que nous ne voulons pas réellement utiliser la ressource: plutôt, nous voulons juste nous assurer qu'elle est fermée lorsque nous en avons fini afin que nous n'ayons pas de développeurs qui bloquent le système. Mais comme tant de choses, ils devaient prendre des décisions de conception et étant en minorité, nous n'avons pas eu la fonctionnalité.

4
corsiKa

Je pense que l'incapacité à utiliser la variable locale a été le déclencheur de l'essai avec ressource.

Avant Java 1.7, vous deviez écrire quelque chose comme ceci:

InputStream in = null;
try {
    in = ....;
} finally {
    if (in != null) {
        in.close();
    }
}

Il y a 2 inconvénients ici:

  1. finally le bloc est ennuyeux et doit être nul pour chaque ressource de fermeture
  2. Nous devons déclarer des ressources en dehors du bloc juste pouvoir y accéder dans le bloc finally. Par conséquent, nous élargissons la portée où les variables sont accessibles, ce qui est une mauvaise pratique.

La syntaxe Try-with-resource résout les deux problèmes:

  1. finally le bloc n'est pas nécessaire du tout.
  2. La variable de ressource reste accessible uniquement dans le bloc try, c'est-à-dire où elle doit être connue.

C'est pourquoi la ressource fermable doit être locale. Sinon, l'un des principaux inconvénients de la syntaxe d'essai avec ressource est "désactivé".

1
AlexR