大家讨论一下finally 和 try里的 return 的先后问题,我看了很多答案都错误

jackyzgm 2004-12-11 08:08:45
有一个网上流传的典型的题(正好我今天笔试也碰到):

问:

try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

【看到很多答案都是:“当然是return前”】 我在笔试时写的是 finally 里的代码return后执行。

看了那些答案的一些程序例证,我认为写的不好,我自己写了个,足可以反对这个说法:
(我认为是return的部分先执行,finally最终是在 try后的)

我的示例:

public class Test22{
public static void main(String[] args){
System.out.print(tt());
}
public static int tt(){
int b = 23;
try{
System.out.println("yes");
return b=88;
}
catch(Exception e){
System.out.println("error : " + e);
}
finally{
if(b>25){
System.out.println("b>25 : "+b);
}
System.out.println("finally");
}
return b;
}
}


执行结果:
yes
b>25 : 88
finally
88

这足以证明在 finally 中的代码执行的时候, b 的值已经变为88,也就是说 return 已执行。

我看了一些人的证明自己观点的例子,但是他们都没有在finally判断是否return已执行,从而都是些敷衍的结论。

希望高人们能给我支持!!
...全文
1051 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
zcjl 2004-12-13
  • 打赏
  • 举报
回复
不好意思,昨天有事出去了,没能及时回复楼主后面的疑问
我把我的理解写到了blog中,http://blog.csdn.net/zcjl/archive/2004/12/12/214123.aspx
有不当之处,还望指正
taolei 2004-12-12
  • 打赏
  • 举报
回复
首先,自己写程序不会象上面那样写的,了解这个问题对写程序没什么意思。

如果就技术层面上讨论这个问题的话,我还是比较认同上面几位分析java pcode的同学。如果没有研究到java 编译或pcode这个深度,讨论这个问题就没什么意思了。
jackyzgm 2004-12-12
  • 打赏
  • 举报
回复

讨论到这里,我应该已经明白了,返回值和return是两码事,最终return还是最后执行,如果这个函数为void的话,那么我们就不用考虑返回值了。 return就是退出函数的意思了。

多谢各位的讨论,问题已经弄明白,网上流传的答案是正确的。 return 最后执行退出函数动作。
无欲则钢 2004-12-12
  • 打赏
  • 举报
回复
知道方法的调用过程,调用前JVM的状态保存在栈中,返回后将恢复保存的状态,就不可能在执行FINALLY里的代码了,先b=88后finally,再return
febchen 2004-12-11
  • 打赏
  • 举报
回复
有些晕了,我到觉得,如果一个方法退出了,那么里面的语句就不会被执行到了。

至于return b=88之类,在没有finally的情况下确实就是结束了,有了finally,就会先做好退出准备,然后等finally结束后在进行下去。

不能写了,回家睡觉了。
febchen 2004-12-11
  • 打赏
  • 举报
回复
你用这个看吧
javap -c Test22

0 bipush 20
2 istore_0
3 iconst_1
4 dup
5 istore_0
6 istore_1
7 jsr 28
10 iload_1
11 ireturn
12 astore_1
13 iconst_2
14 dup
15 istore_0
16 istore_2
17 jsr 28
20 iload_2
21 ireturn
22 astore_3
23 jsr 28
26 aload_3
27 athrow
28 astore 4
30 iconst_3
31 dup
32 istore_0
33 ireturn

我的理解是:

无论怎样执行,都会跳到28(jsr 28)
即finally执行的地方,这里通过astore 4保存返回地址,如果finally中没有return就会是象zcjl() 说得通过ret 4调用1处的return,否则调用2处的return了
truezerg 2004-12-11
  • 打赏
  • 举报
回复
管它什么答案呢, 弄清楚是怎么执行的就行了,不过我的问题谁回答一下

try {
return 1; //1处
} catch (Exception e) {
return 2;
} finally {
return 3; //2处
}

执行结果返回的是 3
但是这个 3 是由 1处 返回的,还是由 2处 返回的? 我不知道了。你告诉我吧。 呵呵
febchen 2004-12-11
  • 打赏
  • 举报
回复
没有说前面的return没有被执行,只是计算了返回值,并没有退出

如下程序,return b=88还是起作用的。

public class Test22{
public static void main(String[] args){
System.out.print(tt());
}
public static int tt(){
int b = 23;
try{
System.out.println("yes");
return b=88;
}
catch(Exception e){
System.out.println("error : " + e);
}
finally{
if(b>25){
System.out.println("b>25 : "+b);
b=10;
}
System.out.println("finally");
return b;
}
}
}

我觉得你认为所谓执行return,就是执行return b=88这条语句,而题目中说的finally在return前运行,这里的return是说退出方法,所以产生如此争论,其实大家都没有错误,只是理解角度问题

此外,好像C#中就不允许在finally中写return了。


truezerg 2004-12-11
  • 打赏
  • 举报
回复
try {
return 1; //1处
} catch (Exception e) {
return 2;
} finally {
return 3; //2处
}

执行结果返回的是 3
但是这个 3 是由 1处 返回的,还是由 2处 返回的? 我不知道了。你告诉我吧。 呵呵
jackyzgm 2004-12-11
  • 打赏
  • 举报
回复
//----------
一个方法只能有1个返回值把,
----------------------------//

返回值是一个,可是确实可以有多个 return 语句。

//------------------
还是应该说明finally先执行了退出方法,所以前面的return也就执行不到了。
-----------------------------------------------------------------------//

这个我觉得不够说服力,因为无法证明执行finally{}之前try{}里的 return 没执行过。

换种说法,也可以这样理解啊, finally{}里的 return 改变了 返回值。
truezerg 2004-12-11
  • 打赏
  • 举报
回复
to: febchen()
如下:
public static void main(String[] args) {
System.out.print(tt());
}
public static int tt(){
int b = 23;
try{
System.out.println("yes");
return b=88;
}
catch(Exception e){
System.out.println("error : " + e);
}
finally{
b=90;
if(b>25){
System.out.println("b>25 : "+b);
b=10;
}
System.out.println("finally");
return b = 11;
}
}

执行结果:

yes
b>25 : 90
finally
11

编译器并没有报告任何问题。在try 中有 return 的情况下,finally里仍然可以写return,只是在 finally 里的 return 之后写任何代码都会报告 unreachable statement 的错误

我的理解,执行顺序是这样的:

首先在 try 中的 return b = 88; 时,执行了 b =88; 这句代码,然后并不返回, 而是把 88 保存在一个临时的地方,并去执行 finally 中的代码。 finally 执行完后,从取出那个临时的地方取出 88 返回。 如果在 finally中有return b = 11; 这句,则在执行到这里时,又把 11 放在了起先保存 88 的位置,这里如果再取的时候,返回结果就是11了。 不过到底这个返回值是由try里的return返回的,还是由finally里的return返回的,我还不太清楚。 我倾向于是由finally里的try返回的
febchen 2004-12-11
  • 打赏
  • 举报
回复
恩,是我看错了
应该可以
这样就返回10了

一个方法只能有1个返回值把,还是应该说明finally先执行了退出方法,所以前面的return也就执行不到了。

水平有限,只好就事论事了。

public class Test22{
public static void main(String[] args){
System.out.print(tt());
}
public static int tt(){
int b = 23;
try{
System.out.println("yes");
return b=88;
}
catch(Exception e){
System.out.println("error : " + e);
}
finally{
b=90;
if(b>25){
System.out.println("b>25 : "+b);
b=10;
}
System.out.println("finally");
return b;
}
}
}


jackyzgm 2004-12-11
  • 打赏
  • 举报
回复
//-------------------------------//
如果你在 try中放了return
那么在finally里就不可能再放置了return了

编译器里会告诉你finally里的retrun是
unreachable statement
//-----------------------------------//

可是还是可以放的啊,你看下以下代码,可以运行,虽然 编译器也说了finally代码不能正常完成,但是还能执行,输出的结果还是finally的return的返回值

public class Test22 {
public static void main(String[] args){
System.out.print(tt());
}

public static int tt(){
try {
return 1;
}
catch(Exception e){}
finally {
return 2;
}
}
}
febchen 2004-12-11
  • 打赏
  • 举报
回复
刚才
zcjl()
说的很清楚了
在finally里是不会改变返回值的

这样说:
1、先计算返回值,并保留了此值(b=88,88被保存了)
2、执行finally,此时可以改变b的值
3、执行return,将保存的88取出并返回

可以仔细看看zcjl() 贴的代码
hengshan 2004-12-11
  • 打赏
  • 举报
回复
把楼主的程序改成如下的形式;
class Test22
{
public static void main(String[] args)
{
System.out.print(tt());
}
public static int tt()
{
int b = 23;
try
{
System.out.println("yes");
return b=88;
}
catch(Exception e)
{
System.out.println("error : " + e);
}
finally
{
if(b>25)
{
System.out.println("b>25 : "+b);
b=120;
}
else System.out.println("finally");
}
b=100;
System.out.println("excute"+b);
return b;
}
}
输出的结果是:
yes
b>25 : 88
88

按照febchen的意思:
未验证的说法:
1、先计算返回值
2、执行finally
3、执行return

关键在对return理解上,个人认为return应该表示返回,退出或者结束方法的意思,如果先执行,那应该先输出返回值才会执行finally

而java对finally的解释也是finally总在方法结束前执行。

tt()的返回值应该是120,怎么还是88呢?
大家继续分析一下,看是怎么回事
febchen 2004-12-11
  • 打赏
  • 举报
回复
如果你在 try中放了return
那么在finally里就不可能再放置了return了

编译器里会告诉你finally里的retrun是
unreachable statement

编译理论里很重要的就是不能有二义性,所以不会出现你说的歧异情况。

其实我的程序和zcjl()的程序都说明了在finally里是不会改变返回值的

可以这么理解
这里return b实际分2次执行
1次是计算返回值
然后看看有无finally之类的事情要做
然后在真正返回(退栈,或者说退出方法)


jackyzgm 2004-12-11
  • 打赏
  • 举报
回复
to zcjl() :

可是,如果finally里有 return 123 ,那么,最后返回的结果就是 123,这样返回结果不也是改变了吗?这样不是也证明了 finally 仍旧是最后执行的吗?
jackyzgm 2004-12-11
  • 打赏
  • 举报
回复
to zcjl() :

阁下意思是: ?

(1)执行return (后面)部分的计算,确定返回结果
(2)执行finally
(2)执行return的退出函数的动作

那么,这里的“return 语句”是指(1)还是(3)呢?? 这个问题的答案就歧义了。
guihu 2004-12-11
  • 打赏
  • 举报
回复
?,代码发不出去?
guihu 2004-12-11
  • 打赏
  • 举报
回复
在网吧,没JDK,其他人试一下这个程序

public static void main(String args[])
{
System.out.println(test());
}
public static String test()
{
String temp="abc";
System.out.println("在test()里,try之前");
try{
System.out.println("在try里");
retrun temp="123";
}
catch(Exception e){}
finally
{
System.our.println("在finally里");
}
System.our.println("在test()里,try之后,temp是:"+temp);
}
加载更多回复(11)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧