try-catch-finally的使用

try-catch-finally语句与return联合使用、try-catch对程序性能的影响。我做了九个对比小实验进行研究,得到以下结论:
**1、finally语句在return语句执行之后return返回之前执行的。
2、finally块中的return语句会覆盖try块中的return返回。
3、如果finally语句中没有return语句覆盖返回值,那么原来的返回值可能因为finally里的修改而改变也可能不变。如果返回基本数据类型不会受finally中的修改影响,如果是返回引用类型会受finally中的修改影响。
4、try块里的return语句在异常的情况下不会被执行,这样具体返回哪个看情况。
5、当发生异常后,catch中的return执行情况与未发生异常时try中return的执行情况完全一样。
6、无异常时候,try-catch几乎不影响程序运行时间。
7、有异常的时候,异常类型匹配越精确越少时间开销。
8、不单纯的用Exception过滤异常、尽量少地在try里面添加代码、尽量不在循环里使用try-catch**
实验只是对try-catch-finally的初步认识,如果深入原理研究还需要研究程序字节码。
第一个问题:finally语句是否一定会执行?
答案:不一定
有两种情况:(1)try之前程序就返回了 (2)try之前程序出错,导致无法向下执行。
代码清单一:

package trycatchfinallyDEMO;
public class FinallyTest {
    static int test() {
       int i = 1;
       if (1 == i) {
           return 0; //first case
       }
       System.out.println("previous statement");
       // i /= 0; //second case
       try {
           System.out.println("try");
           return i;
       } finally {
           System.out.println("finally");
       }
    }

    public static void main(String[] args) {
       System.out.println("return value is:" + test());

    }

}

Output:
first case:return value is:0
second case:报错

以上两种情况,finally语句都没有得到执行。只有与finally相对应的try语句得到执行的时候finally才会执行。
第二个问题:try语句块得到执行的情况下,finally语句一定会得到执行?
答案:否定
代码清单二:

package trycatchfinallyDEMO;

public class FinallyTest {
    static int test() {
       int i = 1;
       System.out.println("previous statement");
       // i /= 0; //second case
       try {
           System.out.println("try");
           System.exit(0);
           return i;
       } finally {
           System.out.println("finally");
       }
    }

    public static void main(String[] args) {
       System.out.println("return value is:" + test());
    }
}

Output:
previous statement
try
当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。
第三个问题:多catch如何匹配捕获
答案:按代码书写顺序寻找最接近的异常进行匹配,找到之后不再进行查找。
代码清单三:

package trycatchfinallyDEMO;

public class myException extends Exception {
    public String toString(){
       return "This is myException!";
    }
}
package trycatchfinallyDEMO;

public class mulcatch {
    static void f() throws myException {
       System.out.println("throw a myException");
       throw new myException();
    }

    static void g() throws Exception {
       System.out.println("throw a Exception");
       throw new Exception();
    }

    public static void main(String[] args) {
       try {
           f();// f()抛出异常得到处理后,下面的输出和g()不会得到执行。
           System.out.println("**********************");
           g();
       } catch (myException e) {
           System.out.println("first catch get it");
       } catch (Exception e) {// Exception是基类,应该放在最后捕获,放在最一开始会出错。
           System.out.println("second catch get it");
       } finally {
           System.out.println("program is end");
       }

       System.out.println("--------------------------------");

       try {
           g(); // 会被最接近的异常类型捕获
           System.out.println("**********************");
           f();
       } catch (myException e) {
           System.out.println("first catch get it");
       } catch (Exception e) {//哪个catch捕获了异常就会由哪个catch处理,其他catch不执行
           System.out.println("second catch get it");
       } finally {
           System.out.println("program is end");
       }

    }
}

Output:
throw a myException
first catch get it
program is end


throw a Exception
second catch get it
program is end
注意:
1、try块中,抛出异常的语句之后的语句不会得到执行。
2、Catch顺序应该是由派生到基类,由小到大捕获,Exception应该最后捕获。
3、会被最接近的异常类型捕获,一旦异常被捕获,其他catch就不会被执行。

第四个问题:finally语句和return语句执行顺序
答案:finally语句在return语句执行之后返回之前执行
在这里系统的讨论下return在try-catch-finally各语句块中的情况。

情况1: try-catch 中的return
代码清单四:

package trycatchfinallyDEMO;

public class tryandcatchwithreturn {
    static int g(int i) {
       try {
           //i /= 0;//此处触发异常之后,就直接执行catch并返回,try里面剩下的语句不再执行。
           System.out.println("g()");
           return i;
       } catch (Exception e) {
           i += 3;
           return i;
       }
    }

    public static void main(String[] args) {
       System.out.println(g(1));
    }

}

Output:
g()
1
如果去掉注释输出就是4,如果注释catch当中的return就会报错,因为编译器认为try里面的return之前可能有异常产生,导致return得不到执行,所以要在函数finally或者函数尾部添加return,或者try-catch里同时添加return

情况2:try-finally中的return
代码清单五:

package trycatchfinallyDEMO;

public class tryandfinallywithreturn {
    static int g(int i) {
       try {
           i += 2;
           System.out.println("g()");
           return i;
       } catch (Exception e) {


       } finally {
           i += 5;
           System.out.println(i);
           //return i;
// finally里也有return,先執行try裏面的return并緩存,然后由于finally里面也有return,所以程序不再返回try进行return
           // 而是直接在finally进行return
       }
    }

    public static void main(String[] agrs) {

       System.out.println(g(1));
    }

}

Output:
g()
8
3
如果在finally中也添加return,那么输出为
g()
8
8
finally中无return时,程序会执行了try块中的return之后,缓存结果,然后执行finally块,最后返回缓存的结果,即使finally中对i进行了修改也没有不会反应到返回值中。如果finally里也有return的话,那么直接在finally里返回值,不在返回缓存结果。

情况3:try-catch-finally中都有return
代码清单六:

package trycatchfinallyDEMO;

public class trycatchfinallywithreturn {
    static int g(int i) {
       try {
           i /= 0;
           System.out.println("g()");
           return i;
       } catch (Exception e) {
           i += 3;
           System.out.println("catch:" + i);
           return i;
       } finally {
           i += 5;
           System.out.println("finally:" + i);
           //return i;//和try-catch中return的情况一样,会缓存catch当中的return,如果finally没有return则返回缓存中的i
           //如果finally中有return,则直接返回。
       }
    }

    public static void main(String[] args) {
       System.out.println(g(1));
    }

}

Output:
catch:4
finally:9
4
如果在finally中添加return,那么输出为
catch:4
finally:9
9
类似于try-catch中return的情况,会缓存catch当中的return,如果finally没有return则返回缓存中的i。如果finally中有return,则直接返回。
第五个问题:返回引用的情况下呢?
代码清单七:

package trycatchfinallyDEMO;

public class recommenddemo {
    static myClass myclass = new myClass();

    static myClass g() {
       try {
           myclass.setTip("world");
           return myclass;
       } catch (Exception e) {
           myclass.setTip("r u ok?");
           return myclass;
       } finally {
           myclass.setTip("tencent");
           //return myclass;
       }
    }

    public static void main(String[] args) {
       System.out.println(g());

    }

}

Output:
hellotencent
可以看到即使finally中不进行return覆盖也会让finally块中操作反应到myclass
第六个问题:try-catch是否影响性能
情况1:不产生异常的时候
代码清单八:

package trycatchfinallyDEMO;

public class trycatchPerformance {

    public static void main(String[] args) {
       int result = 1;
       long starttime1 = System.nanoTime();
       for (int i = 0; i < 20; i++) {
           result *= i;
       }
       long endtime1 = System.nanoTime();
       System.out.println("不使用try-catch所用时间:" + (endtime1 - starttime1));
       result = 1;
       long starttime2 = System.nanoTime();
       try {
           for (int i = 0; i < 20; i++) {
              result *= i;
           }
       } catch (Exception e) {
           // TODO: handle exception
       }
       long endtime2 = System.nanoTime();
       System.out.println("使用try-catch所用時間:" + (endtime2 - starttime2));

    }

}

Output:
不使用try-catch所用时间:1555
使用try-catch所用時間:1556
实验表明在不产生异常的情况下,try-catch不会明显影响程序运行时间。
情况2:产生异常的时候
代码清单九:

package trycatchfinallyDEMO;

public class PerformanceWithEception {

    public static void main(String[] args) {
       int result = 1;
       long starttime1 = System.nanoTime();
       for (int i = 0; i < 20; i++) {
           result *= i;
       }
       long endtime1 = System.nanoTime();
       System.out.println("不使用try-catch所用时间:" + (endtime1 - starttime1));
       result = 1;
       long starttime2 = System.nanoTime();
       try {
           for (int i = 0; i < 20; i++) {
              result *= i;
           }
           throw new mysecondException();
       } catch (Exception e) {
           // TODO: handle exception
       }
       long endtime2 = System.nanoTime();
       System.out.println("使用try-catch Exception所用時間:" + (endtime2 - starttime2));

       long starttime3 = System.nanoTime();
       try {
           for (int i = 0; i < 20; i++) {
              result *= i;
           }
           throw new mysecondException();
       } catch (myException e) {
           // TODO: handle exception
       }catch (Exception e) {
           // TODO: handle exception
       }
       long endtime3 = System.nanoTime();
       System.out.println("使用try-catch myException所用時間:" + (endtime3 - starttime3));

       long starttime4 = System.nanoTime();
       try {
           for (int i = 0; i < 20; i++) {
              result *= i;
           }
           throw new mysecondException();
       } catch (mysecondException e) {
           // TODO: handle exception
       }catch (myException e) {
           // TODO: handle exception
       }
       catch (Exception e) {
           // TODO: handle exception
       }
       long endtime4 = System.nanoTime();
       System.out.println("使用try-catch mysecondException所用時間:" + (endtime4 - starttime4));

    }

}

Output:
不使用try-catch所用时间:622
使用try-catch Exception所用時間:22394
使用try-catch myException所用時間:2488
使用try-catch mysecondException所用時間:2177
由于多出对异常进行类型匹配以及相关处理操作,try-catch在有异常处理时,的确会消耗很多的运行时间。但是与不使用try-catch在时间上不具备可比性,因为它们是功能上的对比。
通过试验可知,catch到的异常类型越接近发生的异常越节省时间,如果单纯的用Exception去过滤会造成很大的时间开销。同时可以想到,尽量少地在try里面添加代码、尽量不在循环里使用try-catch、尽量精确地匹配异常等优化措施,从而提高性能。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页