很多人了解try……catch……finally语法,我们先简单回顾下语法。
代码解读复制代码public static void main(String[] args) {
try{
System.out.println("i'm a try");
System.out.println(1/0);
}catch (Exception e){
System.out.println("i'm a exception");
}finally {
System.out.println("i'm a finally");
}
}
执行结果如下,先执行try代码块,如果有异常再执行catch代码块,最后执行finally语句css
代码解读复制代码i'm a try
i'm a exception
i'm a finally
下面,我们再看一个实例csharp
代码解读复制代码public static void main(String[] args) {
System.out.println(exec());
}
private static String exec(){
String result = "";
try{
System.out.println("i'm a try");
result = "try";
return result;
}catch (Exception e){
System.out.println("i'm a exception");
result = "exception";
}finally {
System.out.println("i'm a finally");
result = "finally";
}
return result;
}
执行结果如下:css
代码解读复制代码i'm a try
i'm a finally
try
请注意,return 只有发生在finally之前,finally中代码才不会改变最终return的数据,如果上述例子中将result = "try";
代码后面的return result;
注释掉,那么结果将会是输出“finally”
我们先看第一个例子csharp
代码解读复制代码public static void main(String[] args) {
System.out.println(exec());
}
private static String exec(){
String result = "";
try{
System.out.println("i'm a try");
result = "try";
System.exit(0);
return result;
}catch (Exception e){
System.out.println("i'm a exception");
result = "exception";
}finally {
System.out.println("i'm a finally");
result = "fianlly";
}
return result;
}
运行结果如下:css
代码解读复制代码i'm a try
本例,说明了之执行了,try部分,然后在System.exit(0);
直接退出程序,后续finally不再执行
我们主线程中启动一个daemon线程,如下csharp
代码解读复制代码public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try{
System.out.println("i'm a try");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
System.out.println("i'm a exception");
}finally {
System.out.println("i'm a finally");
}
}
});
t.setDaemon(true);
t.start();
System.out.println("main end");
}
执行结果如下,可以看到daemon线程中finally并没有打印css
代码解读复制代码main end
i'm a try
此处就大家应该都能理解,就不再说明。
很多人提出那内存溢出或者栈溢出呢?我们简单的写个例子csharp
代码解读复制代码public static void main(String[] args) {
System.out.println(exec());
}
private static String exec(){
String result = "";
try{
System.out.println("i'm a try");
result = "try";
byte[] temp = new byte[1024 * 1024 * 100];
return result;
}catch (Exception e){
System.out.println("i'm a exception");
result = "exception";
}finally {
System.out.println("i'm a finally");
result = "fianlly";
}
return result;
}
将jvm设置如下:
此时运行结果如下,说明内存溢出并不会导致finally不执行,同样栈溢出也不会导致css
代码解读复制代码i'm a try
i'm a finally
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.example.demo.test.FinallyTest.exec(FinallyTest.java:13)
at com.example.demo.test.FinallyTest.main(FinallyTest.java:5)
正常来说,finally的本质是不管 try 语句块正常结束还是异常结束,finally 语句块是保证要执行的。那么finally是如何保证的呢?下面我们继续开始一个例子csharp
代码解读复制代码public static void main(String[] args) {
try{
int a = 1;
}catch (Exception e){
int a = 2;
}finally {
int a = 3;
}
}
我们通过javap
反编译一下:发现,存在多个iconst_3(iconst指令将常量压入栈,iconst_3代表把常量3压入栈中)
根据字节码,我们翻译为java就类似这样ini
代码解读复制代码public static void main(String[] args) {
try{
int a = 1;
int c = 3;//冗余
}catch (Exception e){
int b = 2;
int c = 3;//冗余
}finally {
int c = 3;
}
}
此时我们发现finally通过冗余代码,保证其执行