web-dev-qa-db-ja.com

try-with-resourceにローカル変数が必要なのはなぜですか?

私の質問 を参照して、Java.util.concurrent.locks.LockのAutoCloseableラッパーにリスクがある場合 、なぜtrh try-with-resourcenamedローカル変数が必要です。

私の現在の使用法は次のとおりです。

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

変数lは、tryブロック内では使用されておらず、名前空間を汚染するだけです。覚えていることから、類似のC#usingステートメントは、ローカルの名前付き変数を必要としません。

Tryブロックの最後に閉じられる匿名のローカル変数を使用して、以下がサポートされなかった理由はありますか?

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

@McDowellによるコメントのリンクは、 ブログ投稿コメント で正しい答えを示しています the Java Technology Specification that try-with-resourcesステートメントを導入しました:

JDK 7に戻って、メソッド呼び出しを含むリソースに一般式を使用できるようにするtry-with-resourcesコンストラクトから始めました。ただし、初期ドラフトレビュー( http://jcp.org/aboutJava/communityprocess/edr/jsr334/index.html )で見つかった専門家グループは、

「[try-with-resources statemenbtへの]将来の可能性のある変更により、一般的な式として指定されるリソースのサポートが終了します。一般的な式をリソースとして使用できるようにすることにより、重要な仕様と実装の複雑さが生じます。制限された式識別子であるか、PrimaryNoNewArrayで十分な場合があります。識別子を許可するというより厳しい制限でさえ、はるかに低い限界実装で完全な式(新しいリソース変数の宣言を強制する)を許可するほとんどすべての追加ユーティリティを提供できます。仕様への影響。」

JDK 7の終わりまでに必要なのは、リソースの新しい変数宣言、または既存の最終的な/事実上最終的な変数です。 7つには前者を提供する時間しかありませんでした。 9では、後者も提供しています。

13
Zero3

彼らが検討していたユースケースの中で、ほとんどがブロック内のリソースにアクセスする必要があります。たとえば、ファイルを開く-ファイルの読み取り/書き込み-ファイルを閉じる。ローカル変数が使用されていない多くのユースケースがあると彼らが思ったならば、彼らはこの設計決定をしなかったでしょう。

なぜLockが自動的に閉じることができないのかについては、Doug Leaは構文の問題にあまり関心がなく、難しい問題の解決に重点を置いていると思います。他の人は常に彼のユーティリティに構文糖を追加することができます。

将来的には、try-with-resourceはおそらく時代遅れになり、ラムダに置き換わります。例えば

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

私が望んでいなかったのと同じくらい、その背後にある根拠は、try-with-resourcesは、処分する必要があるアイテムの操作を厳密に目的としているということです。名前付き変数が必要なのは、ブロック内にいる間にその変数を使用して何かを行うことを想定しているためです。コンパイラが「実際にリソースを使用する予定がないのに、なぜtry-with-resourcesを実行しているのですか」と言っているようなものです。

さて、あなたと私は、リソースを実際に使用したくないことを十分に理解しています。むしろ、システムのロックを回避する開発者がいないように、リソースを使い終わったら閉じていることを確認したいだけです。しかし、多くのことのように、彼らは設計上の決定をしなければならず、少数派であったため、機能を取得できませんでした。

4
corsiKa

ローカル変数を使用できないことが、リソースの試行のきっかけになったと思います。

Java 1.7より前のバージョンでは、次のように記述する必要がありました。

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

ここには2つの欠点があります。

  1. finallyブロックは煩わしく、閉じるリソースごとにnullセーフである必要があります
  2. ブロックの外側のリソースは、finallyブロックでそれらにアクセスできるように宣言する必要があります。したがって、変数にアクセスできる範囲を拡大しますが、これは悪い習慣です。

リソースを使用する構文は、両方の問題を解決します。

  1. finallyブロックはまったく必要ありません。
  2. リソース変数は、tryブロックからのみアクセス可能なままです。つまり、リソース変数を知っておく必要があります。

これが、閉鎖可能なリソースがローカルでなければならない理由です。それ以外の場合、try-with-resource構文の主な欠点の1つは「無効」です。

1
AlexR