问题
I have code:
class Test {
public static void main(final String [] args) {
System.out.println(foo());
}
private static int foo() {
int a = 0;
try {
++a;
return a;
} finally {
a = 10;
}
}
}
I can't uderstand why 1 is printed.
回答1:
try {
++a;
return a; // 1 is returned here
} finally {
a = 10; // a is assigned with 10 later.
}
The value of a
is incremented and returned in the try
block itself. Post this return
, the value of a
is re-assigned in the finally
block. And that is the reason, why it prints 1.
Quoting from the docs. This should help you understand it more clearly.
Compiling finally
Compilation of a try-finally statement is similar to that of try-catch. Prior to transferring control outside the try statement, whether that transfer is normal or abrupt, because an exception has been thrown, the finally clause must first be executed. For this simple example:
void tryFinally() {
try {
tryItOut();
} finally {
wrapItUp();
}
}
The compiled code is:
Method void tryFinally()
0 aload_0 // Beginning of try block
1 invokevirtual #6 // Method Example.tryItOut()V
4 jsr 14 // Call finally block
7 return // End of try block
8 astore_1 // Beginning of handler for any throw
9 jsr 14 // Call finally block
12 aload_1 // Push thrown value
13 athrow // ...and rethrow value to the invoker
14 astore_2 // Beginning of finally block
15 aload_0 // Push this
16 invokevirtual #5 // Method Example.wrapItUp()V
19 ret 2 // Return from finally block
Exception table:
From To Target Type
0 4 8 any
There are four ways for control to pass outside of the try statement:
- by falling through the bottom of that block
- by returning
- by executing a break or continue statement
- by raising an exception.
回答2:
This happens because the finally
block of a try..catch..finally runs after the code within the try..catch
has completed
You are assigned the value in finally
and before that you returned in try
The code in finally always executes,but you are already returned the value in try
.
try {
++a;
return a;
} finally {
a = 10;
}
Now a
value is 10
, after the return
.
Though not a good practice, Just for demo.
int a= 0;
try {
++a;
return a;
} finally {
a = 10;
return a;
}
Now it return
's 10
.
Edit:
Your doubt : Why unreacable error not coming ?
in try-catch-finally
the blocks are different. Do the same in same block and see.
try {
++a;
return a;
a=100; //compiler error.
} finally {
a = 10;
}
Edit2
From java language specification of try-catch-finally :
A try statement executes a block. If a value is thrown and the try statement has one or more catch clauses that can catch it, then control will be transferred to the first such catch clause. If the try statement has a finally clause, then another block of code is executed, no matter whether the try block completes normally or abruptly, and no matter whether a catch clause is first given control.
回答3:
class Test {
public static void main(final String [] args) {
System.out.println(foo());
}
private static int foo() {
int a = 0;
try {
++a;
return a;
} finally {
a = 10;
}
}
}
In the above code, value returned will be 1 because, finally will not update the value returned in the try block.
class Test {
public static void main(final String [] args) {
System.out.println(foo());
}
private static int foo() {
int a = 0;
try {
++a;
return a;
} finally {
a = 10;
return a;
}
}
}
The above code will return the value as 10, because, the value is returned from finally again.
回答4:
JVM is a stack-based machine. It push and pop value onto the stack. I decompiled Test
class, to understand how it work.
private static int foo();
Code:
0: iconst_0 //push 0 to stack
1: istore_0 //store 0 in the local variable 'a'(numbered 0). a==0
2: iinc 0, 1 //increase the local variable 'a'(numbered 0) by 1. a==1;
5: iload_0 //push value of the local variable 'a' onto the stack;
6: istore_1 //store 1 in the local variable that not be declared(numbered 1);
7: bipush 10 //push 10 onto the stack;
9: istore_0 //store 10 in the local variable 'a'
10: iload_1 //push onto stack value==1 of local variable that not be declared
11: ireturn //return 1
12: astore_2
13: bipush 10
15: istore_0
16: aload_2
17: athrow
Exception table:
// not interesting ...
回答5:
Simply...you have not mentioned return a in or after final block. Final block is executed in the end and value of a is set to 10, but you have not coded to return this new value! Try below code to get your expected output:
class Test {
public static void main(final String [] args) {
System.out.println(foo());
}
private static int foo() {
int a = 0;
try {
++a;
return a;
} finally {
a = 10;
return a;
}
}
}
来源:https://stackoverflow.com/questions/19651860/why-is-printed-1