One 、finally The external expression of statement block execution
1.1. Gosling Personally to finally Description of
a finally clause is always entered with a reason. That reason may be that the try code finished normally, that it executed a control flow statement such as return, or that an exception was thrown in code executed in the Try block. The reason is remembered when the finally clause exits by falling out the bottom. However, if the finally block creates its own reason to leave by executing a control flow statement (such as break or return) or by throwing an exception, that reason supersedes the original one, and the original reason is forgotten. For example, consider the following code:
try {
// … do something …
return 1;
} finally {
return 2;
}
When the Try block executes its return, the finally block is entered with the “reason” of returning the value 1. However, inside the finally block the value 2 is returned, so the initial intention is forgotten. In fact, if any of the other code in the try block had thrown an exception, the result would still be to return 2. If the finally block did not return a value but simply fell out the bottom, the “return the value 1 ″ reason would be remembered and carried out.
1. 2. According to Java To understand and translate
Get into finally The reasons for the clause are as follows :
- Statement executes normally
- Executed in a process control statement
- Execute statement throws an exception The cause will be recorded finally Statement execution time .
further ,finally Clause because of some circumstances out of the current execution of the process control statements are :
- break
- return
- Throw an exception
The above three situations will replace the original execution statement (try Medium return, break, Throw an exception ) , The third part will complete the experiment
The following procedure is an example :
try {
// … do something …
return 1;
} finally {
return 2;
}
When try Execute in statement block return sentence , finally The statement will get 1 This value , However ,finally The sentence inside return 2 Will be in
return 1 Pre execution . The original return 1 The statement will be overridden . It is worth noting that , In the above example program :
- stay try An arbitrary exception occurred in the statement ,finally The sentence inside return 2 Always execute .
- If finally There is no Return a value , that return 1; Will be executed normally
【 Returns a value , It’s a general statement , The second part will explain 】
1.3. Example program experiment
1.3.1 try No exception in , try and finally Held at the same time return sentence
public static int testFinallyWithReturn() {
try {
return 10;
} finally {
return 1000;
}
}
return 1000
1.3.2 try There’s something unusual in , try and finally Held at the same time return sentence
public static int testFinallyWithExceptionButReturn(int a) {
try {
// ArithmeticException Will be finally Of return Words eat
a = a / 0;
return 10;
} finally {
// 1. return Can cover throw exceptions
// 2. throw Statement and return Sentences cannot be tied at the same level
return 1000;
}
}
Don’t throw exceptions , At the same time return to 1000
1.3.3 try There’s something unusual in , try and finally Throw an exception at the same time
public static int testFinallyWithNotReturn(int a) {
try {
a = a / 0; // ArithmeticException Will be finally Of return Words eat
return a + 10;
} finally {
// 1. return Can cover throw exceptions
// 2. throw Statement and return Sentences cannot be tied at the same level
throw new RuntimeException("finally Exception in statement block ");
}
}
Exception in thread “main” java.lang.RuntimeException: finally Exception in statement block
- Use more intuitive test cases to test
public static int testCatchFinallyWithException(int a) {
try {
throw new RuntimeException("try Exception in statement block ");
//a = a / 0;
} finally {
throw new RuntimeException("finally Exception in statement block ");
}
}
Exception in thread “main” java.lang.RuntimeException: finally Exception in statement block
- Re evolution , As expected
public static int testCatchFinallyWithException(int a){
try {
throw new RuntimeException("try Exception in statement block ");
} catch (Exception e) {
// e.printStackTrace();
throw new RuntimeException("catch Exception in statement ");
} finally {
throw new RuntimeException("finally Exception in statement block ");
}
}
Exception in thread “main” java.lang.RuntimeException: finally Exception in statement block
- The pit to be filled : Although as expected , But output stack information ,try and catch An exception was thrown .
- Don’t print the stack , Only finally It’s abnormal
public static int testCatchFinallyWithException(int a){
try {
throw new RuntimeException("try Exception in statement block ");
} catch (Exception e) {
e.printStackTrace();
try {
throw new RuntimeException("catch Exception in statement ");
} catch (Exception e2){
e2.printStackTrace();
}
} finally {
throw new RuntimeException("finally Exception in statement block ");
}
}
[ Print the stack information to see the first two sentences ]
java.lang.RuntimeException: try Exception in statement block
java.lang.RuntimeException: catch Exception in statement
Exception in thread “main” java.lang.RuntimeException: finally Exception in statement block
1.3.4 finally In the implementation of continue and break
public static int testFinallyWithContinue(int a) {
int i = 0;
while (i < 2) {
try {
// ArithmeticException Will be finally Of continue Words eat
a = a / 0;
} finally {
i++;
continue;
}
}
return i;
}
public static int testFinallyWithBreak(int a) {
int i = 0;
while (i < 2) {
try {
// ArithmeticException Will be finally Of break Words eat
a = a / 0;
} finally {
break;
}
}
return i;
}
No exceptions
Two 、finally The extension of external performance
2.1 Yes Gasling A supplement to the description
Tested , The conclusion is consistent with the expectation . among Gasling A more general statement ( Or the translation is not in place ) :
” finally In the block *** Return a value *** It can cover the original value “
among break and continue Did not return a value , But also successfully put try The exception in the statement is eaten
Another better explanation is ( Reprint )
“ among return and throw Transfer program control to their callers (invoker), and break and continue Control of is transferred within the current method ”
2.2 Official website 《 The Java Tutorials 》 This proves that
The finally Block
The finally block always executes when the try block exits. This ensures that the finally block is executed even if an
unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to
avoid having cleanup code accidentally bypassed by a return,continue, or break. Putting cleanup code in a finally block is
always a good practice, even when no exceptions are anticipated.
Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if
the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the
application as a whole continues.
3、 … and 、 The reason is
3.1 Compile to bytecode instructions
public static int getValue() {
int i = 1;
try {
return i;
} finally {
i++;
}
}
}
public static int getValue();
Code:
0: iconst_1
1: istore_0
2: iload_0
3: istore_1 // finally Relevant instructions
4: iinc 0, 1 // Weird two identical instructions -> The problem is illustrated below
7: iload_1
8: ireturn
9: astore_2
10: iinc 0, 1 // Weird two identical instructions
13: aload_2
14: athrow
Exception table:
from to target type
2 4 9 any
9 10 9 any
}
getValue() : 1
3.2 Diagram of bytecode instruction process
3.2.1 getValue() Normal execution process
public static int getValue();
Code:
0: iconst_1 // i ( Operands ) Push
1: istore_0 // index = 0 Of i store Go to the local variable table
2: iload_0 // index = 0 Of i load Go to the operand stack 【 At this time, the operation stack is empty 】
3: istore_1 // index = 1 Of i store Go to the local variable table ( Copy index = 0 Of i)/* finally Related bytecode instructions */
4: iinc 0, 1 // index = 0 Of i Self increasing 1 /* finally Related bytecode instructions */
7: iload_1 // index = 1 Of i load Go to the operand stack 【 At this time, the operation stack element is 1 individual 】
8: ireturn // index = 1 Of i Return from operand to caller
9: astore_2 // Exception handling related
10: iinc 0, 1 /* finally Related bytecode instructions */
13: aload_2 // Exception handling related
14: athrow // Exception handling related
Exception table:
from to target type
2 4 9 any
9 10 9 any
}
Be able to see clearly : finally Statement block related bytecode instructions are inserted into return The statement before ,
finally Statement block i yes Copied index = 0 Of i Generate index = 1 Of i Go to the local variable table
linc 0,1 explain The auto increment operation is in index = 0 Of i On That is to say try Statement i, iload_1 hold index = 0 Of i Push into the operand stack
ireturn in ***return 了 i The top element of the stack of operands index = 1 Of i *** , Value nature is 1 了
In general : finally Made a copy of X(i) Variable Born into Y(i), Yes X(i++), It is Y(i)
3.2.2 getValue() Exception execution process
Exception table:
from to target type
2 4 9 any // If from 2 To 4 This command has an exception , From 9 Start with instructions to deal with .
9 10 9 any
3.2.3 getValue() Of finally Add return
public static int getValue() {
int i = 1;
try {
return i;
} finally {
i++;
return i;
}
}
jdk1.8 Two changes after compiling
Left : added return | Right : Not added return
added return after Summary
- added return iload The bytecode instruction changes , It changes the final return of It’s not a copy
- Exception handling athrow Turned into ireturn, On the other hand, it explains in try An exception in a statement block will give finally Medium return eat
therefore , The above code returns 2
3.2.3 getValue() Of finally Of return Before adding other code
- Just add it to finally
As expected ,try The statement block is synchronized with finally New code in .
- Added variable declaration with the same name
- Code corresponds to bytecode
- Code corresponds to bytecode
- 【 Point one 】 Concerned about the first 8 9 10 12 That’s ok
8 iload_1
9 istore_3
10 bipush 34 // push A constant 34 Go to the operand stack
12 istore 4 // hold 34 Fill in slot = 4 Local variable table of , It's obviously a new variable
【 Key point 2 】 Return to the former ,load 了 finally Variables created , That is to say, the operation copy , Return copy
17 iload 4
19 ireturn
- Further, it can be found that , If finally Inside created try Variable with the same name in q, The code behind is also finally Created in the local method table q Variable
- It is further proved that the variable with the same name + return Under the circumstances : Operation copy , Return copy ;
Bytecode instruction summary
- finally Inside No addition return, operation try The variables in the
1.1 Copy a finally The code in , Insert try return Before
1.2 Copy first try The variables in the X Go to the local variable table , Become Y, Right again X operation .
1.3 【 The key 】 The return is Y, That is to say, the operation X But not back , Or return the value before the operation Y
summary :finally Not inside return, The return is finally Created copy of , and finally All operations are on the original values
- finally Inside Add return, operation try The variables in the
2.1 Copy a finally The code in , Insert try return Before
2.2 The principle of operation is the same as 1.2
2.3 【 The key 】load 了 X, Again ireturn. It’s not going back finally Created copy of , It’s the actual return of the manipulated X
- finally in Add return, And declare and try Variable with the same name in , Operating variables
3.1 【 The key 】load and store 了 try Variable with the same name in 【 new slot】, The operation is new slot, That’s the new copy
It’s also a copy , It’s just that the bytecode used is different
3.2 The original ireturn It’s the same
3.3 Put in exception handling throw To modify a return
3.4 【 The key 】load 了 【 new slot】 Go to the operand stack , That’s the new copy , Finally, return the copy
summary : stay finally The statement is made. try The variables already in , Copies a copy of the value of the variable with the same name , All operations are for this replica .
expand
No, catch sentence , Where is the exception handling ?( Reprint )
Actually , Even without catch sentence ,Java The compiler compiles bytecode with default exception handling , Don’t forget , Except for the exceptions that need to be caught , There may also be exceptions that do not need to be caught ( Such as :RunTimeException and Error).
When from 2 To 4 When there is an exception in this instruction , There will be a exception object , And push it to the top of the current operand stack . Next is astore_2 This Directive , It takes charge of exception Object to local variable table 2 The location of , And then execute finally Sentence block , stay finally After the execution of statement block , Again by aload_2 This instruction puts the pre stored exception Object to the operand stack , Finally by athrow The instruction returns it to the caller of the method (main).
- Analyze exception handling part
Exception table:
from to target type
2 4 9 any
9 10 9 any
Code:
0: iconst_1
1: istore_0
2: iload_0 // 2, 3 ,4 Any exception , iload_1 and ireturn Do not carry out ,
// I can't go back index = 0 Of i, Will jump to 9 Start , Finally arrive 14 Throw out
3: istore_1 /* finally stay try Bytecode instructions inserted in */
4: iinc 0, 1 /* finally stay try Bytecode instructions inserted in */
7: iload_1
8: ireturn
9: astore_2 // Exception handling related
10: iinc 0, 1 /* finally Expected bytecode instruction */
13: aload_2 // Exception handling related
14: athrow // Exception handling related
replay
Which explains why try Exception in statement Will give finally Medium return 、 break 、 continue eat .
It also explains finally Final return The value of try return Before , That is to say, it covers try Medium return
Of course ,try If it’s a function Such as return function(); Equivalent to int temp = function(); return temp;
function() Will execute , however temp The value of cannot return
Auxiliary materials : finally The underlying implementation of the compilation
《 The JavaTM Virtual Machine Specification, Second Edition 》 in 7.13 section Compiling finally Said ( Reprinted translation )
actually ,Java Virtual opportunity puts finally Statement block as subroutine( For this subroutine I don’t know how to translate it , Just don’t translate , To avoid ambiguity and misunderstanding .) Insert directly into try Statement block or catch Before the control transfer statement of statement block . however , There is another factor that cannot be ignored , That’s execution subroutine( That is to say finally Sentence block ) Before ,try perhaps catch Statement blocks retain their return values to the local variable table (Local Variable Table) in . stay subroutine After execution , Restore the reserved return value to the operand stack , And then through return perhaps throw Statement returns it to the caller of the method (invoker). Please note that , We mentioned before that return、throw and break、continue The difference between , For this rule ( Keep the return value ), Only applicable to return and throw sentence , Do not apply to break and continue sentence , Because they have no return value at all .
The above can explain the bytecode instruction Generative logic 了
Reference material :https://www.ibm.com/developerworks/cn/java/j-lo-finally/
notes : The above links are reproduced in the pictures and some translations