2010-02-22 4 views
40

Donné ce code:Retours multiples: Lequel définit la valeur de retour finale?

String test() { 
    try { 
     return "1"; 
    } finally { 
     return "2"; 
    } 
} 

Est-ce que les spécifications linguistiques définissent la valeur de retour d'un appel à test()? En d'autres termes: est-ce toujours la même chose dans chaque JVM?

Dans la JVM Sun, la valeur de retour est 2, mais je veux être sûr que cela ne dépend pas de VM.

Répondre

41

Oui, le language spec définit "2" comme résultat. Si une machine virtuelle le fait différemment, elle n'est pas conforme aux spécifications.

La plupart des compilateurs s'en plaindront. Eclipse, par exemple, prétend que le bloc de retour ne sera jamais exécuté, mais c'est faux.

Il est scandaleusement mauvaise pratique d'écrire du code comme ça, ne jamais le faire :)

+2

je me suis abstenue de la minute où je pensais, mais j'étais toujours curieux :) –

13

Le bloc finally sera toujours exécuté, sauf dans l'exemple suivant:

String test() { 
    try { 
     System.exit(0); 
    } finally { 
     return "2"; 
    } 
} 

Dans ce cas, la machine virtuelle Java s'arrête, sans exécuter le bloc finally. Dans votre exemple, la valeur de retour sera 2.

+0

Comme cette réponse – john

7

Oui, si vous renvoyez quelque chose du bloc finally, il remplacera tout ce que vous auriez pu renvoyer du bloc try ou catch.

La même chose est vraie également pour exceptions. Si vous lancez quelque chose dans le bloc finally, cette exception remplacera toute exception levée dans le bloc try ou catch. Veillez donc à ne jamais jeter quelque chose dans le bloc finally, car il peut masquer la raison originale d'un échec.

+1

une autre chose intéressante est que si quelque chose est renvoyé de finalement en utilisant 'return' alors toute exception levée est mis au rebut. – sttaq

18

Oui, la Java Language Specification est très clair sur cette question (14.20.2):

Une déclaration d'essai avec un bloc finally est exécuté par la première exécution du bloc d'essai. Ensuite, il y a un choix:

  • Si l'exécution du bloc try se termine normalement, [...]
  • Si l'exécution du bloc try se termine brusquement à cause d'un jet d'une valeur V, [.. .]
  • Si l'exécution du bloc try se termine brusquement pour toute autre raison R, alors le bloc finally est exécuté. Ensuite, il y a un choix:
    • Si le bloc finally se termine normalement, [...]
    • Si le bloc finally se termine brusquement pour une raison S, l'instruction try se termine brusquement pour une raison S (et la raison R est rejeté).
0

Vous pouvez consulter le lien ci-dessous. J'espère qu'il fournira tous les détails:

http://www.programmerinterview.com/index.php/java-questions/will-finally-run-after-return/

Il dit bloc finally exécute toujours essayer même ou bloc catch retour est relevé. Et si finalement block a aussi l'instruction return alors cela remplacera l'instruction return qui est dans try ou catch block et dans ce cas toute exception lancée dans try/catch sera rejetée (mauvaise approche).

Merci, Chethan

2

Après avoir lu le bytecode du programme, le code est le suivant:

Le bloc finally est inline avant l'instruction de retour du bloc d'essai, de sorte que le retour de la finalement bloc s'exécute en premier et l'instruction de retour d'origine ne le fait jamais.

pour le programme:

String test() { 
     try { 
      System.out.println("try"); 
      return "1"; 
     } finally { 
      System.out.println("finally"); 
      return "2"; 
     } 
    } 

Il convertit:

String test() 
    { 
     System.out.println("try"); 
     String s = "1"; //temporary variable 
     System.out.println("finally"); 
     return "2"; 
     Exception exception; 
     exception; 
     System.out.println("finally"); 
     return "2"; 
    } 

Et Pour le programme: avec bloc catch:

String test() { 

     try { 
      System.out.println("try"); 
      return "1"; 
     } catch (RuntimeException e) { 
      System.out.println("catch"); 
      return "2"; 
     } finally { 
      System.out.println("finally"); 
      return "3"; 
     } 
    } 

Converti à:

String test() 
    { 
     System.out.println("try"); 
     String s = "1"; 
     System.out.println("finally"); 
     return "3"; 
     RuntimeException e; 
     e; 
     System.out.println("catch"); 
     String s1 = "2"; 
     System.out.println("finally"); 
     return "3"; 
     Exception exception; 
     exception; 
     System.out.println("finally"); 
     return "3"; 
    } 

Remarque: Conforme à l'aide de JDK 1.7 & Décompilé à l'aide de Cavaj.

+1

'throw e' ne sera jamais accessible. – Viks

+0

merci @Viks, j'ai ajouté plus d'idées après quelques recherches. –

Questions connexes