例えば:
try
{
SomeObject someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //can't access someObject!
ただし、try/catch
ブロックの前に宣言すると、正常に機能します。
SomeObject someObject;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //works fine
私はこれの設計上の理由を疑問に思っています。 try/catch
ブロック内で作成されたオブジェクトが、メソッドの他の部分のスコープ内にないのはなぜですか?たぶん、Exceptions
がスローされるのを監視する以外に、try/catch
がどのように機能するかを深く理解していないのかもしれません。
Try/catchブロック内で作成されたオブジェクトが、メソッドの他の部分のスコープ内にないのはなぜですか?
彼らです。 変数宣言済みtry/catch
ブロック内は、すべてが同じ理由で、包含ブロックのスコープ内にありません他の変数宣言は、それらが発生するスコープに対してローカルです。それが仕様で定義されている方法です。 :-)(コメントへの返信を含む、以下の詳細。)
以下は、外部でアクセス可能なtry/catch
内に作成されたオブジェクトです。
SomeObject someObject = null;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); // This is fine -- unless the SomeObject
// constructor threw the exception, in which
// case someObject will be null
違いに注意してください。 variableがdeclaredである場合、それが存在するスコープを定義します。ここで、objectはcreatedでした。
しかし、上記のメソッド名などに基づいて、より便利な構造は次のようになります。
SomeObject someObject = new SomeObject();
try
{
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod();
あなたのコメントを再:
Try/catchブロック用に別のスコープが作成された理由について混乱していると思います。
Javaでは、すべてのブロックがスコープを作成します。 if
の本体、else
の本体、while
の本体など。これらはすべて、新しいネストされた変数スコープを作成します。
if (foo) {
SomeObject bar = new SomeObject();
}
bar.doSomething(); // <== Compilation error, `bar` is not defined
(実際、制御構造のないブロックでも作成されます。)
考えてみると、それは理にかなっています:いくつかのブロックは、if
またはwhile
の本体を定義するような条件付きです。上記のif
で、bar
は(foo
の値に応じて)宣言されている場合と宣言されていない場合があります。 foo
のランタイム値。そのため、おそらく一貫性のために、Javaの設計者はallブロックに新しいネストされたスコープを作成させました。JavaScriptの設計者他の方法で行きました—ブロックスコープはまだありませんが、追加されています—そしてそのアプローチalso人を混乱させる。)
Javaでは、{ }
ペア、新しいスコープを作成できます。
以下を考慮してください
class ScopeTest {
public static void main(String[] args) {
int i = 0;
{ int j = 0; System.out.println(j); }
{ int j = 2; System.out.println(j); }
}
}
Try/catchはこのイディオムの後に続き、{ }
作成されるペア。
括弧で囲まれていないifステートメントのフォローアップに対応するには、以下を考慮してください。
class MultiRTree {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) String s = new String("hello");
}
}
結果として
c:\files\j>javac ScopeTest.Java
ScopeTest.Java:4: not a statement
if(b) String s = new String("hello");
^
ScopeTest.Java:4: ';' expected
if(b) String s = new String("hello");
^
2 errors
ただし、これは問題なくコンパイルされます。
class ScopeTest {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) new String("hello");
}
}
JLSの第14章のセクション9によると、次のように定義されている場合
IfThenStatement:
if ( Expression ) Statement
ステートメントは(14.5)として定義されます
Statement:
StatementWithoutTrailingSubstatement
LabeledStatement
IfThenStatement
IfThenElseStatement
WhileStatement
ForStatement
StatementWithoutTrailingSubstatement:
Block
EmptyStatement
ExpressionStatement
AssertStatement
SwitchStatement
DoStatement
BreakStatement
ContinueStatement
ReturnStatement
SynchronizedStatement
ThrowStatement
TryStatement
したがって、ブロック、式ステートメント、または空のステートメントは問題ありません。ただし、宣言(第6章で定義)は文の文法には含まれません。
変数またはオブジェクトのスコープは、それが定義されているスコープ(中括弧{}で定義)内にあります。
Try catchはエラーをスローできる新しいスコープを開始するため、try catch内で定義されたオブジェクトはそのスコープ外では使用できません。
try/catch
は、ブロックレベルの要素であるという単純な理由で新しいスコープを作成します。実際、単に{}
メソッド内でランダムに実行すると、独自のローカルスコープを持つ新しいコードブロックが作成されます。
ブラケット '{'を使用するたびに、C++とJavaの両方で新しいスコープを表現しています。操作を試行しようとすると、内部設定が必要になり、名前をスコープすることで、多くのクリーンアップなしでtryブロックからすばやくジャンプできます。
一部の言語では、名前の競合が発生しない限り(Pythonなど)、スコープ外のスコープ変数にアクセスできますが、これには少し異なる内部スタック構造が必要であり、それでもなお、try catchのコストが増加する可能性があります。
また、Java-他の多くの回答が指摘しているように、スコープ定義がどのように定義されているかということです。