J'ai une classe Java simple comme indiqué ci-dessous:
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
Et la sortie de ce code est la suivante:
Entry in finally Block
dev
Pourquoi n'est-il s
pas remplacé dans le finally
bloc, tout en contrôlant la sortie imprimée?
java
try-finally
Dev
la source
la source
s
avant de modifier sa valeur.finally
bloc , contrairement à C # (ce que vous ne pouvez pas)Réponses:
Le
try
bloc se termine par l'exécution de l'return
instruction et la valeur des
au moment où l'return
instruction s'exécute est la valeur renvoyée par la méthode. Le fait que lafinally
clause modifie ultérieurement la valeur des
(une fois l'return
instruction terminée) ne modifie pas (à ce stade) la valeur de retour.Notez que ce qui précède traite des modifications de la valeur de
s
lui - même dans lefinally
bloc, pas de l'objet qui faits
référence. Sis
était une référence à un objet mutable (ce quiString
ne l'est pas) et que le contenu de l'objet était modifié dans lefinally
bloc, alors ces modifications seraient vues dans la valeur renvoyée.Les règles détaillées sur la façon dont tout cela fonctionne se trouvent dans la section 14.20.2 de la spécification du langage Java . Notez que l'exécution d'une
return
instruction compte comme une fin brusque dutry
bloc (la section commençant " Si l'exécution du bloc try se termine brusquement pour toute autre raison R .... " s'applique). Voir la section 14.17 du JLS pour savoir pourquoi unereturn
instruction est une fin brusque d'un bloc.À titre de détail supplémentaire: si le
try
bloc et lefinally
bloc d'unetry-finally
instruction se terminent brusquement à cause d'return
instructions, les règles suivantes du §14.20.2 s'appliquent:Le résultat est que l'
return
instruction dans lefinally
bloc détermine la valeur de retour de l'try-finally
instruction entière et la valeur renvoyée dutry
bloc est ignorée. Une chose similaire se produit dans unetry-catch-finally
instruction si letry
bloc lève une exception, il est intercepté par uncatch
bloc et lecatch
bloc et lefinally
bloc ont desreturn
instructions.la source
finally
bloc ne modifie pas l'objet retourné (leStringBuilder
) mais il peut modifier les éléments internes de l'objet. Lefinally
bloc s'exécute avant que la méthode ne retourne réellement (même si l'return
instruction est terminée), donc ces modifications se produisent avant que le code appelant ne voie la valeur retournée.StringBuilder
,List
,Set
, ad nauseam): si vous modifiez le contenu dans lefinally
bloc, alors ces changements sont visibles dans le code d' appel lorsque la méthode enfin des sorties.Parce que la valeur de retour est placée sur la pile avant l'appel de finally.
la source
=
ne le muterait pas.finally
bloc d'OP n'a pas affecté la valeur de retour. Je pense que ce que templatetypedef aurait pu atteindre (bien que ce ne soit pas clair) est que, parce que la valeur retournée est une référence à un objet immuable, même la modification du code dans lefinally
bloc (autre que l'utilisation d'une autrereturn
instruction) ne pourrait pas affecter le valeur renvoyée par la méthode.Si nous regardons à l'intérieur du bytecode, nous remarquerons que JDK a fait une optimisation significative et que la méthode foo () ressemble à:
Et bytecode:
java a préservé la chaîne "dev" d'être modifiée avant de revenir. En fait, il n'y a finalement aucun blocage du tout.
la source
Il y a 2 choses à noter ici:
la source
finally
clause, cela serait vu dans le code appelant. Toutefois, si vous attribuez un nouveau tampon de chaîne às
, le comportement serait le même que maintenant.Je change un peu votre code pour prouver le point de Ted.
Comme vous pouvez le voir, la sortie
s
est en effet modifiée mais après le retour.Production:
la source
Techniquement parlant, le
return
dans le bloc try ne sera pas ignoré si unfinally
bloc est défini, seulement si ce bloc finally inclut également unreturn
.C'est une décision de conception douteuse qui était probablement une erreur rétrospectivement (un peu comme les références pouvant être annulées / mutables par défaut et, selon certains, vérifiées). À bien des égards, ce comportement est exactement cohérent avec la compréhension familière de ce que
finally
signifie - «peu importe ce qui se passe au préalable dans letry
bloc, exécutez toujours ce code». Par conséquent, si vous retournez vrai à partir d'unfinally
bloc, l'effet global doit toujours être àreturn s
, non?En général, c'est rarement un bon idiome, et vous devriez utiliser
finally
généreusement des blocs pour nettoyer / fermer les ressources, mais rarement, voire jamais, en renvoyer une valeur.la source
Essayez ceci: Si vous souhaitez imprimer la valeur de remplacement de s.
la source