¿Por qué un bloque Try / Catch crea un nuevo scope variable?

Por ejemplo:

try { SomeObject someObject = new SomeObject(); someObject.dangerousMethod(); } catch(Exception e) { } someObject.anotherMethod(); //can't access someObject! 

Pero puedes declararlo antes del bloque try/catch y luego funciona bien:

 SomeObject someObject; try { someObject = new SomeObject(); someObject.dangerousMethod(); } catch(Exception e) { } someObject.anotherMethod(); //works fine 

Me pregunto el motivo del diseño para esto. ¿Por qué los objetos creados dentro del bloque try/catch no están en el scope con el rest del método? Tal vez no entiendo en el fondo cómo funciona un try/catch además de solo observar Exceptions arrojadas.

¿Por qué los objetos creados dentro del bloque try / catch no están en el scope con el rest del método?

Son. Las variables declaradas dentro del bloque try/catch no están dentro del scope en el bloque contenedor, por la misma razón que todas las demás declaraciones de variables son locales para el ámbito en el que ocurren: así es como lo define la especificación. 🙂 (Más abajo, incluida una respuesta a su comentario).

Aquí hay un objeto creado dentro de un try/catch que se puede acceder fuera de él:

 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 

Tenga en cuenta la diferencia. Donde se declara la variable define el ámbito en el que existe, no donde se creó el objeto .

Pero en base a los nombres de métodos y demás, la estructura más útil para eso sería:

 SomeObject someObject = new SomeObject(); try { someObject.dangerousMethod(); } catch(Exception e) { } someObject.anotherMethod(); 

Re su comentario:

Supongo que estoy confundido sobre por qué se ha creado otro scope para un bloque try / catch.

En Java, todos los bloques crean scope. El cuerpo de un if , el cuerpo de else , de un while , etc. – todos crean un nuevo scope variable nested:

 if (foo) { SomeObject bar = new SomeObject(); } bar.doSomething(); // < == Compilation error, `bar` is not defined 

(De hecho, incluso un bloque sin estructura de control crea uno).

Y si lo piensas bien, tiene sentido: algunos bloques son condicionales, como el que define el cuerpo de un if o while . En el anterior if , la bar puede o no haber sido declarada (dependiendo del valor de foo ), lo cual no tiene sentido porque, por supuesto, el comstackdor no tiene ningún concepto del valor de tiempo de ejecución de foo . Probablemente por coherencia, los diseñadores de Java decidieron que todos los bloques crearan un nuevo scope nested. (El diseñador de JavaScript fue por el otro lado - no hay ningún scope de bloque en absoluto, aunque está siendo agregado - y ese enfoque también confunde a las personas).

En Java, cada vez que tenga un { } par, puede crear un nuevo scope.

Considera lo siguiente

 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); } } } 

El try / catch solo sigue este modismo y hace que se cree un { } par.

Para responder a su seguimiento de una statement if sin corchetes, considere:

 class MultiRTree { public static void main(String...args) { boolean b = args.length == 0; if(b) String s = new String("hello"); } } 

resultados en

 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 

Sin embargo, esto comstackrá muy bien.

 class ScopeTest { public static void main(String...args) { boolean b = args.length == 0; if(b) new String("hello"); } } 

Por qué esto es así, de acuerdo con el capítulo 14 de JLS, sección 9, si se define como:

 IfThenStatement: if ( Expression ) Statement 

Y Statement se define como (14.5)

 Statement: StatementWithoutTrailingSubstatement LabeledStatement IfThenStatement IfThenElseStatement WhileStatement ForStatement StatementWithoutTrailingSubstatement: Block EmptyStatement ExpressionStatement AssertStatement SwitchStatement DoStatement BreakStatement ContinueStatement ReturnStatement SynchronizedStatement ThrowStatement TryStatement 

Entonces, un bloque, statement de expresión o statement vacía están bien. Pero una statement (definida en el capítulo 6) no está en la gramática de enunciado.

El scope de una variable u objeto está en el scope (definido por llaves {}) en el que está definido.

Como try catch inicia un nuevo ámbito en el que se puede generar algún error, por lo que los objetos definidos dentro de try catch no están disponibles fuera de su scope.

try/catch crea un nuevo ámbito por la sencilla razón de que es un elemento de nivel de bloque. De hecho, simplemente colocando {} solo al azar dentro de un método creará un nuevo bloque de código con su propio ámbito local.

Cada vez que utilice un corchete ‘{‘ está expresando un nuevo scope tanto en C ++ como en Java. Intentar probar una operación requiere una configuración interna y el scope de los nombres permite saltos rápidos fuera del bloque try sin mucha limpieza.

Algunos idiomas le permitirán acceder a esas variables de ámbito fuera del scope, siempre que no exista un conflicto de nombres (como en Python), pero esto requiere una estructura de stack interna ligeramente diferente y aún podría boost los costos de la captura de prueba independientemente.

También es solo cómo se definen las definiciones de scope en Java, como se señaló en muchas otras respuestas.