Par exemple:
try
{
SomeObject someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //can't access someObject!
Mais vous pouvez le déclarer avant le try/catch
bloquer et puis ça marche bien:
SomeObject someObject;
try
{
someObject = new SomeObject();
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod(); //works fine
Je me demande simplement la raison du design. Pourquoi les objets sont-ils créés dans le try/catch
le bloc n'est pas dans la portée avec le reste de la méthode? Peut-être que je ne comprends pas au fond comment un try/catch
fonctionne en plus de simplement regarder Exceptions
levé.
Pourquoi les objets créés dans le bloc try/catch ne sont-ils pas dans la portée du reste de la méthode?
Elles sont. Les variables déclarées dans le bloc try/catch
Ne sont pas dans la portée du bloc conteneur, pour la même raison que toutes les autres déclarations de variables sont locales à la portée dans laquelle elles se produisent: C'est ainsi que la spécification la définit. :-) (Plus ci-dessous, y compris une réponse à votre commentaire.)
Voici un objet créé dans un try/catch
Qui est accessible en dehors de celui-ci:
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
Notez la différence. Lorsque la variable est déclarée définit la portée dans laquelle elle existe, pas où l'objet a été créé .
Mais sur la base des noms de méthode et autres, la structure la plus utile serait:
SomeObject someObject = new SomeObject();
try
{
someObject.dangerousMethod();
}
catch(Exception e)
{
}
someObject.anotherMethod();
Re votre commentaire:
Je suppose que je ne comprends pas pourquoi une autre étendue a même été créée pour un bloc try/catch.
En Java, tous les blocs créent une portée. Le corps d'un if
, le corps d'un else
, d'un while
, etc. - ils créent tous une nouvelle portée de variable imbriquée:
if (foo) {
SomeObject bar = new SomeObject();
}
bar.doSomething(); // <== Compilation error, `bar` is not defined
(En fait, même un bloc sans aucune structure de contrôle en crée un.)
Et si vous y réfléchissez, cela a du sens: certains blocs sont conditionnels, comme celui définissant le corps d'un if
ou while
. Dans ce qui précède if
, bar
peut ou non avoir été déclaré (selon la valeur de foo
), ce qui n'a aucun sens car bien sûr le compilateur n'a pas de concept de la valeur d'exécution de foo
. Donc, probablement pour des raisons de cohérence, les concepteurs de Java est allé de pair avec tous les blocs créent une nouvelle portée imbriquée. (Le concepteur de JavaScript est allé dans l'autre sens - il n'y a pas du tout d'étendue de bloc, bien qu'il soit ajouté - et cette approche également confond les gens.)
En Java, chaque fois que vous disposez d'un { }
paire, vous pouvez créer une nouvelle étendue.
Considérer ce qui suit
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); }
}
}
Le try/catch suit juste cet idiome et applique un { }
paire à créer.
Pour répondre à votre suivi d'une déclaration if non entre crochets, pensez à:
class MultiRTree {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) String s = new String("hello");
}
}
résulte 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
Cependant, cela se compilera très bien.
class ScopeTest {
public static void main(String...args) {
boolean b = args.length == 0;
if(b) new String("hello");
}
}
Pourquoi en est-il ainsi, selon le chapitre 14 de JLS, section 9, si est défini comme:
IfThenStatement:
if ( Expression ) Statement
Et l'instruction est définie comme (14.5)
Statement:
StatementWithoutTrailingSubstatement
LabeledStatement
IfThenStatement
IfThenElseStatement
WhileStatement
ForStatement
StatementWithoutTrailingSubstatement:
Block
EmptyStatement
ExpressionStatement
AssertStatement
SwitchStatement
DoStatement
BreakStatement
ContinueStatement
ReturnStatement
SynchronizedStatement
ThrowStatement
TryStatement
Donc, un bloc, une expression ou une instruction vide sont très bien. Mais une déclaration (définie au chapitre 6) n'est pas dans la grammaire de la déclaration.
La portée d'une variable ou d'un objet se trouve dans la portée (définie par des accolades {}) dans laquelle elle est définie.
Étant donné que try catch lance une nouvelle portée où une erreur peut être levée de sorte que les objets définis à l'intérieur de try catch ne sont pas disponibles en dehors de sa portée.
try/catch
crée une nouvelle portée pour la simple raison qu'il s'agit d'un élément de niveau bloc. En fait, il suffit de placer {}
juste au hasard dans une méthode créera un nouveau bloc de code avec sa propre portée locale.
Chaque fois que vous utilisez une parenthèse '{', vous exprimez une nouvelle portée en C++ et en Java. Vous essayez d'essayer une opération nécessite une configuration interne et l'étendue des noms permet de sauter rapidement hors du bloc d'essai sans beaucoup de nettoyage.
Certaines langues vous permettent d'accéder à ces variables de portée en dehors de la portée tant qu'il n'y a pas de conflit de nom (comme en Python), mais cela nécessite une structure de pile interne légèrement différente et pourrait quand même augmenter les coûts de la capture d'essai.
C'est aussi la façon dont les définitions de portée sont définies dans Java - comme l'ont souligné de nombreuses autres réponses.