Warum erfordert try-with-resource eine lokale Variable?

Lesezeit: 5 Minuten

Benutzer-Avatar
Elende Variable

In Bezug auf meine Frage Gibt es ein Risiko in einem AutoCloseable-Wrapper für java.util.concurrent.locks.Lock? Ich frage mich, warum die try-with-resource-Anweisung a genannt lokale Variable überhaupt.

Meine derzeitige Nutzung ist wie folgt:

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

Die Variable l wird innerhalb des try-Blocks nicht verwendet und verschmutzt nur den Namensraum. Soweit ich mich erinnern kann, das analoge C # using-Anweisung erfordert keine lokale benannte Variable.

Gibt es einen Grund, warum Folgendes nicht unterstützt werden konnte, mit einer anonymen lokalen Variablen, die am Ende des try-Blocks geschlossen wird?

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

  • Das ist in Java 9 angesprochen. Sehen JDK-8068949.

    – McDowell

    9. Februar 2015 um 16:35 Uhr

  • @McDowell Java 9 adressiert das aktuelle Verhalten, das die Definition von a erfordert Neu Variable, indem die Verwendung von an erlaubt wird vorhandenen effektiv letzte Variable. Aus Ihrem Link geht nicht hervor, dass Java 9 automatisch schließbare Ressourcen unterstützt ohne sichtbare Kennung. (Hier diskutiert.)

    – William Preis

    24. März 2017 um 22:04 Uhr


Der Link im Kommentar von @McDowell verrät die richtige Antwort ein Blogpost-Kommentar von Joe Darcy, der führte die Java Technology Specification die die try-with-resources-Anweisung einführte:

Zurück in JDK 7 haben wir mit einem try-with-resources-Konstrukt begonnen, das es ermöglichte, einen allgemeinen Ausdruck für die Ressource zu verwenden, einschließlich eines Methodenaufrufs. Die Expertengruppe stellte jedoch bei der frühen Überprüfung des Entwurfs fest (http://jcp.org/aboutJava/communityprocess/edr/jsr334/index.html) das

“Eine mögliche zukünftige Änderung [to the try-with-resources statemenbt] stellt die Unterstützung für eine Ressource ein, die als allgemeiner Ausdruck angegeben werden soll. Nichttriviale Spezifikations- und Implementierungskomplexitäten ergeben sich daraus, dass zugelassen wird, dass ein allgemeiner Ausdruck als Ressource verwendet wird. Ein eingeschränkter Ausdruck, der ein Bezeichner oder ein PrimaryNoNewArray sein könnte, kann ausreichen. Selbst die strengere Einschränkung, nur einen Bezeichner zuzulassen, kann fast den gesamten zusätzlichen Nutzen bieten, einen vollständigen Ausdruck zuzulassen (über das Erzwingen der Deklaration einer neuen Ressourcenvariablen) bei einer viel geringeren marginalen Implementierungs- und Spezifikationsauswirkung.

Am Ende von JDK 7 wollten wir eine neue Variablendeklaration für die Ressource oder eine vorhandene finale / effektiv finale Variable. Wir hatten nur Zeit, ersteres in 7 bereitzustellen; in 9 bieten wir auch letzteres an.

  • Java9 unterstützt immer noch nicht den Fall von OP.

    – ZhongYu

    13. Januar 2016 um 4:12 Uhr

Unter den Anwendungsfällen, die sie in Betracht gezogen haben, müssten die meisten auf die Ressource innerhalb des Blocks zugreifen, z. B. Datei öffnen – Datei lesen/schreiben – Datei schließen. Sie hätten diese Designentscheidung nicht getroffen, wenn sie dachten, dass es viele Anwendungsfälle gibt, in denen die lokale Variable nicht verwendet wird.

Was die Frage betrifft, warum Lock nicht automatisch geschlossen werden kann, denke ich, dass Doug Lea sich nicht allzu sehr um Syntaxangelegenheiten kümmert, er konzentriert sich auf die Lösung des schwierigen Problems. Andere können seinen Dienstprogrammen immer noch Syntaxzucker hinzufügen.

Mit Blick auf die Zukunft wird Try-with-Ressource wahrscheinlich aus der Mode kommen und durch Lambda ersetzt werden. Zum Beispiel

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

  • +1 für die Lambda-Nutzung. Der Rest ist spekulativ. Obwohl es wahrscheinlich richtig ist, interessiert es mich mehr, ob es Gründe gibt, warum dies nicht möglich ist.

    – Elende Variable

    16. Mai 2013 um 15:07 Uhr

  • Sicher, es geht, es ist nur mehr Arbeit, sie dachten nicht, dass es das wert ist.

    – ZhongYu

    16. Mai 2013 um 15:50 Uhr

  • IMHO ist dies ein Missbrauch von Lambdas. Es gibt keinen Vorteil, und es erschwert das Lesen des Codes. Tu das nicht.

    – Erich Schubert

    7. November 2014 um 16:18 Uhr

  • Sie hätten diese Designentscheidung nicht getroffen …“: Ja, würden sie. Aus Zeitmangel. Siehe meine Antwort.

    – Null3

    13. Januar 2016 um 2:31 Uhr

  • Die Idee mit Lambda-Ausdrücken ist nett, hat aber mehrere große Probleme: 1) das schrittweise Durchlaufen des Codes im Debugger wird mühsam 2) die Aufrufhierarchie ist mit den Lambda-Aufrufen überladen 3) die Codevervollständigung innerhalb von Lambas ist derzeit suboptimal (zumindest in Eclipse-Neon).

    – Alan47

    14. November 2016 um 9:27 Uhr

So sehr ich es mir auch wünsche, der Grund dafür ist, dass das Try-with-Ressourcen ausschließlich für Operationen an dem zu entsorgenden Gegenstand gedacht ist. Es erfordert eine benannte Variable, weil es erwartet, dass Sie etwas mit dieser Variablen tun, während Sie sich innerhalb des Blocks befinden. Ich denke, es ist so, als würde der Compiler sagen: “Wenn Sie nicht vorhaben, die Ressource tatsächlich zu verwenden, warum machen Sie dann einen Versuch mit Ressourcen?”

Jetzt wissen Sie und ich ganz genau, dass wir die Ressource nicht wirklich verwenden wollen: Wir wollen vielmehr nur sicherstellen, dass sie geschlossen ist, wenn wir damit fertig sind, damit keine Entwickler herumlaufen und das System sperren. Aber wie bei so vielen Dingen mussten sie Designentscheidungen treffen, und da wir in der Minderheit waren, bekamen wir das Feature nicht.

  • ich bin Verwendung von Ressourcen – für seine Nebenwirkungen in seiner <init>() und close()

    – Elende Variable

    27. August 2013 um 17:59 Uhr

  • Aber Sie verwenden es nicht innerhalb des Blocks, was der primäre Anwendungsfall für Try-with-Ressourcen ist. Ich finde es auch frustrierend, aber es ist halt so. Sie können sich einige Immobilien sparen, indem Sie import staticing Ihre Lock-Klasse.

    – corsiKa

    27. August 2013 um 19:17 Uhr

  • Es gibt viele Gründe, die Ressource nicht explizit innerhalb des Blocks zu verwenden, zum Beispiel könnte es eine Sperre sein; oder in einem ThreadLocal gehalten.

    – Stefan Reich

    2. Dezember 2017 um 16:27 Uhr

  • Da stimme ich dir voll und ganz zu Stefan. Wie gesagt, ich finde es auch frustrierend. Es scheint, dass init und close für die Designer dieser Funktion nicht als “im Block” betrachtet werden.

    – corsiKa

    2. Dezember 2017 um 18:23 Uhr

  • Das war eine absolut schreckliche Entscheidung. Versuche mit Ressourcen könnten verwendet werden, um Blockschließungen vorzunehmen. So eine Kurzsichtigkeit

    – Enerccio

    13. Mai 2021 um 7:52 Uhr

Ich denke, dass die Unfähigkeit, lokale Variablen zu verwenden, der Auslöser für Try-with-Ressource war.

Vor Java 1.7 musste man so etwas schreiben:

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

Hier gibt es 2 Nachteile:

  1. finally block ist lästig und muss für jede schließende Ressource nullsicher sein
  2. Wir müssen Ressourcen außerhalb des Blocks deklarieren, um nur darauf zugreifen zu können finally Block. Daher erweitern wir den Bereich, in dem die Variablen zugänglich sind, was eine schlechte Praxis ist.

Try-with-Ressource-Syntax löst beide Probleme:

  1. finally Block wird überhaupt nicht benötigt.
  2. Die Ressourcenvariable bleibt zugänglich in try Block nur, dh wo es bekannt sein sollte.

Aus diesem Grund muss die schließbare Ressource lokal sein. Andernfalls ist einer der Hauptnachteile der try-with-resource-Syntax “deaktiviert”.

1140930cookie-checkWarum erfordert try-with-resource eine lokale Variable?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy