一)java的异常处理机制(try…catch…finally)

先看一段代码

public class TestException {@SuppressWarnings("finally")boolean testEx() throws Exception {boolean ret = true;try {ret = testEx1();} catch (Exception e) {System.out.println("testEx, catch exception");ret = false;throw e;} finally {System.out.println("testEx, finally; return value=" + ret);return ret;}}boolean testEx1() throws Exception {boolean ret = true;try {ret = testEx2();if (!ret) {return false;}System.out.println("testEx1, at the end of try");return ret;} catch (Exception e) {System.out.println("testEx1, catch exception");ret = false;throw e;} finally {System.out.println("testEx1, finally; return value=" + ret);return ret;}}boolean testEx2() throws Exception {boolean ret = true;try {int b = 12;int c;for (int i = 2; i >= -2; i--) {c = b / i;System.out.println("i=" + i);}return true;} catch (Exception e) {System.out.println("testEx2, catch exception");ret = false;throw e;} finally {System.out.println("testEx2, finally; return value=" + ret);return ret;}}public static void main(String[] args) {TestException testException1 = new TestException();try {testException1.testEx();} catch (Exception e) {e.printStackTrace();}}
}

事实上,实际运行出来的答案与预想的有点不太一样

i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false

二)Try-catch概念理论

1)基本概念

例外是在程序运行过程中发生的异常事件,比如除0溢出、数组越界、文件找不到等,这些事件的发生将阻止程序的正常运行。为了加强程序的执行效率,程序设计时,必须考虑到可能发生的异常事件并做出相应的处理。C语言中,通过使用if语句来判断是否出现了例外,同时,调用函数通过被调用函数的返回值感知在被调用函数中产生的例外事件并进行处理。全程变量ErroNo常常用来反映一个异常事件的类型。但是,这种错误处理机制会导致不少问题。
          Java通过面向对象的方法来处理例外。在一个方法的运行过程中,如果发生了例外,则这个方法生成代表该例外的一个对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理这一例外。我们把生成例外对象并把它提交给运行时系统的过程称为抛弃(throw)一个例外。运行时系统在方法的调用栈中查找,从生成例外的方法开始进行回朔,直到找到包含相应例外处理的方法为止,这一个过程称为捕获(catch)一个例外。

2)源头Throwable

       用面向对象的方法处理例外,就必须建立类的层次。类Throwable位于这一类层次的最顶层,只有它的后代才可以做为一个例外被抛弃。图1表示了例外处理的类层次。
         从图中可以看出,类Throwable有两个直接子类:Error和Exception。Error类对象(如动态连接错误等),由Java虚拟机生成并抛弃(通常,Java程序不对这类例外进行处理);Exception类对象是Java程序处理或抛弃的对象。它有各种不同的子类分别对应于不同类型的例外。其中类RuntimeException代表运行时由Java虚拟机生成的例外,如算术运算例外ArithmeticException(由除0错等导致)、数组越界例外ArrayIndexOutOfBoundsException等;其它则为非运行时例外,如输入输出例外IOException等。Java编译器要求Java程序必须捕获或声明所有的非运行时例外,但对运行时例外可以不做处理。
3)异常处理关键字

Java的异常处理是通过5个关键字来实现的:try,catch,throw,throws,finally

  1】Try

    try语句用大括号{}指定了一段代码,该段代码可能会抛弃一个或多个例外。

    2】catch

     catch语句的参数类似于方法的声明,包括一个例外类型和一个例外对象。例外类型必须为Throwable类的子类,它指明了catch语句所处理的例外类型,例外对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。
    catch语句可以有多个,分别处理不同类的例外。Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。这里,类型匹配指catch所处理的例外类型与生成的例外对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般。
    也可以用一个catch语句处理多个例外类型,这时它的例外类型参数应该是这多个例外类型的父类,程序设计中要根据具体的情况来选择catch语句的例外处理类型。 

         3】finally

         try所限定的代码中,当抛弃一个例外时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛弃或不抛弃例外,也无论catch语句的例外类型是否与所抛弃的例外的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。
    4】Throws

throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。对大多数Exception子类来说,Java编译器会强迫你声明在一个成员函数中抛出的异常的类型。如果异常的类型是Error或RuntimeException, 或它们的子类,这个规则不起作用,因为这在程序的正常部分中是不期待出现的。 如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型。
    5】Throw

throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

三)try的嵌套

       可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部,写另一个try语句保护其他代码。每当遇到一个try语句,异常的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,堆栈就会展开,直到遇到有处理这种异常的try语句。

    参见如下例子:

public class ExceptionCatch {static void procedure() {try {int a = 0;int b = 42/a;} catch(java.lang.ArithmeticException e) {System.out.println("in procedure, catch ArithmeticException: " + e);}}public static void main(String args[]) {try {procedure();} catch(java.lang. Exception e) {System.out.println("in main, catch Exception: " + e);}}
}

结果:

in procedure, catch ArithmeticException: java.lang.ArithmeticException: / by zero

成员函数procedure里有自己的try/catch控制,所以main不用去处理ArrayIndexOutOfBoundsException;

当然如果如同最开始我们做测试的例子一样,在procedure中catch到异常时使用throwe;语句将异常抛出,那么main当然还是能够捕捉并处理这个procedure抛出来的异常。例如在procedure函数的catch中的System.out语句后面增加throwe;语句之后,执行结果就变为:

in procedure, catch ArithmeticException: java.lang.ArithmeticException: / by zero
in main, catch Exception: java.lang.ArithmeticException: / by zero

常见try-catch-finally嵌套使用方式

public class TestCatch {public static void main(String[] args) throws Exception {txt2String(new File("D:test.txt"));}/*** 本方法无法处理抛出的异常,处理某段代码抛出的异常,代码块中捕抓到的异常* @param file* @return* @throws Exception*/public static String txt2String(File file) throws Exception {StringBuilder result = new StringBuilder();//代码块的总try-catch异常try {// 1.构造一个BufferedReader类来读取文件BufferedReader br = new BufferedReader(new FileReader(file));String s = null;while ((s = br.readLine()) != null) {// 使用readLine方法,一次读一行result.append(System.lineSeparator() + s);}//2代码块內嵌异常try {} catch (Exception e) {}} catch (Exception e) {try {//3代码块异常处理出现的异常} catch (Exception e2) {// TODO: handle exception}e.printStackTrace();}finally {//4.結束这段代码處理发生的异常try {} catch (Exception e2) {// TODO: handle exception}}return result.toString();}
}

四)try-catch-finally程序块的执行流程以及执行结果

     try-catch-finally程序块的执行流程以及执行结果比较复杂。
首先执行的是try语句块中的语句,这时可能会有以下三种情况:
1.如果try块中所有语句正常执行完毕,那么finally块的居于就会被执行,这时分为以下两种情况:
1】如果finally块执行顺利,那么整个try-catch-finally程序块正常完成。
    2】如果finally块由于原因R突然中止,那么try-catch-finally程序块的结局是“由于原因R突然中止(completesabruptly)”

2.如果try语句块在执行过程中碰到异常V,这时又分为两种情况进行处理:
-->如果异常V能够被与try相应的catch块catch到,那么第一个catch到这个异常的catch块(也是离try最近的一个与异常V匹配的catch块)将被执行;这时就会有两种执行结果:
 1>如果catch块执行正常,那么finally块将会被执行,这时分为两种情况:
     1】如果finally块执行顺利,那么整个try-catch-finally程序块正常完成。
     2】如果finally块由于原因R突然中止,那么try-catch-finally程序块的结局是“由于原因R突然中止(completesabruptly)”
 2>如果catch块由于原因R突然中止,那么finally模块将被执行,分为两种情况:
     1】如果如果finally块执行顺利,那么整个try-catch-finally程序块的结局是“由于原因R突然中止(completesabruptly)”。
     2】如果finally块由于原因S突然中止,那么整个try-catch-finally程序块的结局是“由于原因S突然中止(completesabruptly)”,原因R将被抛弃。
    (注意,这里就正好和我们的例子相符合,虽然我们在testEx2中使用throwe抛出了异常,但是由于testEx2中有finally块,而finally块的执行结果是completeabruptly的(别小看这个用得最多的return,它也是一种导致completeabruptly的原因之一啊——后文中有关于导致completeabruptly的原因分析),所以整个try-catch-finally程序块的结果是“completeabruptly”,所以在testEx1中调用testEx2时是捕捉不到testEx1中抛出的那个异常的,而只能将finally中的return结果获取到。
      如果在你的代码中期望通过捕捉被调用的下级函数的异常来给定返回值,那么一定要注意你所调用的下级函数中的finally语句,它有可能会使你throw出来的异常并不能真正被上级调用函数可见的。当然这种情况是可以避免的,以testEx2为例:如果你一定要使用finally而且又要将catch中throw的e在testEx1中被捕获到,那么你去掉testEx2中的finally中的return就可以了。
这个事情已经在OMC2.0的MIB中出现过啦:服务器的异常不能完全被反馈到客户端。)
-->如果异常V没有catch块与之匹配,那么finally模块将被执行,分为两种情况:
      1】如果finally块执行顺利,那么整个try-catch-finally程序块的结局就是“由于抛出异常V而突然中止”。
      2】如果finally块由于原因S突然中止,那么整个try-catch-finally程序块的结局是“由于原因S突然中止”,异常V将被抛弃。

3.如果try由于其他原因R突然中止(completes abruptly),那么finally块被执行,分为两种情况:
       1>如果finally块执行顺利,那么整个try-catch-finally程序块的结局是“由于原因R突然中止”。
      2>如果finally块由于原因S突然中止,那么整个try-catch-finally程序块的结局是“由于原因S突然中止”,原因R将被抛弃。

五) try-catch-finally程序块中的return

      从上面的try-catch-finally程序块的执行流程以及执行结果一节中可以看出无论try或catch中发生了什么情况,finally都是会被执行的,那么写在try或者catch中的return语句也就不会真正的从该函数中跳出了,它的作用在这种情况下就变成了将控制权(语句流程)转到finally块中;这种情况下一定要注意返回值的处理。

例如,catch 体里遇到 return 是怎么处理? finally 体遇到 return 怎么办?finally 体里有 System.exit() 方法怎么处理?当 catch 和 finally 体里同时遇上 return 怎么办?
      或者,在try或者catch中return false了,而在finally中又return true,那么这种情况下不要期待你的try或者catch中的return false的返回值false被上级调用函数获取到,上级调用函数能够获取到的只是finally中的返回值,因为try或者catch中的return语句只是转移控制权的作用。

处理异常的时候不是每次都把它 throws 掉就完事了,很多时候异常是需要我们自己来 catch 并针对所抛出的 Exception 做一些后续的处理工作。

1)抛出Exception,没有finally,当 catch 遇上 return

/*** @version 2017年11月15日 下午8:05:44*/
public class CatchTest {public static void main(String[] args) {// TODO Auto-generated method stubcatchTest();}// catch 后续处理工作public static boolean catchMethod() {System.out.print("call catchMethod and return  --->>  ");return false;}// finally后续处理工作public static void finallyMethod() {System.out.println();System.out.print("call finallyMethod and do something  --->>  ");}public static boolean catchTest() {try {int i = 10 / 0; // 抛出 Exception,后续处理被拒绝System.out.println("i vaule is : " + i);return true; // Exception 已经抛出,没有获得被执行的机会} catch (Exception e) {System.out.println(" -- Exception --");return catchMethod(); // Exception 抛出,获得了调用方法并返回方法值的机会}}}

结果:

 -- Exception --
call catchMethod and return  --->> 

2)抛出 Exception,当 catch 体里有 returnfinally 体的代码块将在catch 执行 return 之前被执行

 public static boolean catchFinallyTest1() {try {int i = 10 / 0; // 抛出 Exception,后续处理被拒绝System.out.println("i vaule is : " + i);return true; // Exception 已经抛出,没有获得被执行的机会} catch (Exception e) {System.out.println(" -- Exception --");return catchMethod(); // Exception 抛出,获得了调用方法的机会,但方法值在 finally 执行完后才返回} finally {finallyMethod(); // Exception 抛出,finally 代码块将在 catch 执行 return 之前被执行}}

结果

 -- Exception --
call catchMethod and return  --->>
call finallyMethod and do something  --->> 

3)不抛 Exception,当 finally 代码块里面遇上returnfinally 执行完后将结束整个方法

 public static boolean catchFinallyTest2() {try {int i = 10 / 2; // 不抛出 ExceptionSystem.out.println("i vaule is : " + i);return true; // 获得被执行的机会,但执行需要在 finally 执行完成之后才能被执行} catch (Exception e) {System.out.println(" -- Exception --");return catchMethod();} finally {finallyMethod();return false; // finally 中含有 return 语句,这个 return 将结束这个方法,不会在执行完之后再跳回 try 或 catch// 继续执行,方法到此结束,返回 false}}

结果

i vaule is : 5call finallyMethod and do something  --->>  

4)不抛 Exception,当 finally 代码块里面遇上System.exit() 方法将结束和终止整个程序,而不只是方法

 public static boolean finallyExitTest() {try {int i = 10 / 2; // 不抛出 ExceptionSystem.out.println("i vaule is : " + i);return true; // 获得被执行的机会,但由于 finally 已经终止程序,返回值没有机会被返回} catch (Exception e) {System.out.println(" -- Exception --");return true;} finally {finallyMethod();System.exit(0);// finally 中含有 System.exit() 语句,System.exit() 将退出整个程序,程序将被终止}}

结果:

i vaule is : 5call finallyMethod and do something  --->> 

5)抛出Exception,当 catch 和 finally 同时遇上 return,catch 的 return 返回值将不会被返回,finally的 return 语句将结束整个方法并返回

public static boolean finallyTest1() {try {int i = 10 / 0; // 抛出 Exception,后续处理被拒绝System.out.println("i vaule is : " + i);return true; // Exception 已经抛出,没有获得被执行的机会} catch (Exception e) {System.out.println(" -- Exception --");return true; // Exception 已经抛出,获得被执行的机会,但返回操作将被 finally 截断} finally {finallyMethod();return false; // return 将结束整个方法,返回 false}}

结果:

 -- Exception --call finallyMethod and do something  --->> 

6)不抛出 Exception,当 finally 遇上 returntry return 返回值将不会被返回,finally return 语句将结束整个方法并返回

 public static boolean finallyTest2() {try {int i = 10 / 2; // 不抛出 ExceptionSystem.out.println("i vaule is : " + i);return true; // 获得被执行的机会,但返回将被 finally 截断} catch (Exception e) {System.out.println(" -- Exception --");return true;} finally {finallyMethod();return false; // return 将结束这个方法,不会在执行完之后再跳回 try 或 catch 继续执行,返回 false}}

结果

i vaule is : 5call finallyMethod and do something  --->>  

总结:方法需要返回值的java 的异常处理中,在不抛出异常的情况下,程序执行完 try 里面的代码块之后,该方法并不会立即结束,而是继续试图去寻找该方法有没有 finally 的代码块:

1】如果没有 finally 代码块,整个方法在执行完 try 代码块后返回相应的值来结束整个方法;
   2】如果有 finally 代码块,此时程序执行到 try 代码块里的 return 语句之时并不会立即执行 return,而是先去执行 finally 代码块里的代码,
         1)若 finally 代码块里没有return 或没有能够终止程序的代码,程序将在执行完 finally 代码块代码之后再返回 try 代码块执行 return 语句来结束整个方法;
         2)若 finally 代码块里有 return 或含有能够终止程序的代码,方法将在执行完 finally 之后被结束,不再跳回 try 代码块执行 return。
     在抛出异常的情况下,原理也是和上面的一样的,把上面的 try 换成 catch 去理解即可。

参考:1)http://www.blogjava.net/fancydeepin/archive/2012/07/08/java_try-catch-finally.html

  2)http://blog.csdn.net/idulx/article/details/7332588










关于中断try-catch-finally的小结相关推荐

  1. arm Linux 中断管理机制

    关键词:GIC.IAR.EOI.SGI/PPI/SPI.中断映射.中断异常向量.中断上下文.内核中断线程.中断注册. 1.1 ARM支持中断类型 ARM GIC-v2支持三种类型的中断: SGI:软件 ...

  2. S5PV210体系结构与接口07:中断系统编程

    目录 1. 什么是按键 1.1 按键原理与连接 1.2 按键的2种响应方式 1.2.1 轮询方式 1.2.2 中断方式 1.3 轮询方式处理按键解析 1.4 按键消抖 1.4.1 按键抖动 1.4.2 ...

  3. interrupt()中断对LockSupport.park()的影响

    文章目录 原理简单讲解 调用park()与unpark() park/unpark实现的伪代码 park/unpark的实验 interrupt()与park() interrupt()实现的伪代码 ...

  4. soc(九) 中断控制器

    中断控制器在SOC中的位置 中断控制器需要做什么事情 从某个 简单中断处理器 的角度考虑 整个过程 既然处理中断的最核心模块是 中断控制器 , 那么 我们就应该了解 中断控制器的典型工作流程 . 在了 ...

  5. Java并发之线程池ThreadPoolExecutor源码分析学习

    线程池学习 以下所有内容以及源码分析都是基于JDK1.8的,请知悉. ​ 我写博客就真的比较没有顺序了,这可能跟我的学习方式有关,我自己也觉得这样挺不好的,但是没办法说服自己去改变,所以也只能这样想到 ...

  6. 异常全家桶来咯,异常捕获,异常抛出,自定义异常

    1.捕获异常: 在Java中,凡是可能抛出异常的语句,都可以用try...catch捕获.把可能发生异常的语句放在try{...}中,然后使用catch捕获对应的Exception及其子类. 1.多c ...

  7. 锁与并发工具包与线程池与LockSupport与Fork/Join框架与并行流串行流与阻塞队列与JPS,jstack命令查看死锁查看线程状态与AQS个人笔记九

    朝闻道,夕死可矣 本文共计 86564字,估计阅读时长1小时 点击进入->Thread源码万字逐行解析 文章目录 本文共计 86564字,估计阅读时长1小时 一锁 二Java中13个原子操作类 ...

  8. 线上接口经常超时,我用线程池+ FutureTask解决了,YYDS

    欢迎关注方志朋的博客,回复"666"获面试宝典 之前红包权益领取查询的接口超时了,因为有用户订购的权益有点多 解决方案 用线程池+ FutureTask将1个查询拆分成多个小查询 ...

  9. JAVA线程池的分析和使用

    1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提 ...

  10. 接口经常超时?线程池+ FutureTask来解决!

    之前红包权益领取查询的接口超时了,因为有用户订购的权益有点多 解决方案 用线程池+ FutureTask将1个查询拆分成多个小查询 选择FutureTask是因为它具有仅执行1次run()方法的特性( ...

最新文章

  1. 东京奥运会73枚动态图标刷爆朋友圈,中国网友怒赞:不愧是设计大国!
  2. php在dw中设置按钮圆角,Dreamweaver怎么用CSS制作圆角按钮?
  3. linux登出系统,讲解Linux操作系统进入与退出系统方法
  4. Keil的可重定位段
  5. RocketMQ错误消息重试策略之重试情况的分析
  6. 关于HTTP协议的几个问题
  7. springboot上传文件过大,全局异常捕获,客户端没有返回值
  8. 关于DX中纹理平移的一个小问题
  9. 教程 | 如何使用Docker、TensorFlow目标检测API和OpenCV实现实时目标检测和视频处理
  10. <论文阅读>TARE: A Hierarchical Framework for Efficiently Exploring Complex 3D Environments
  11. 徐艳(帮别人名字作诗)
  12. 11.9 至 11.17 四道典型题记录: Counter 弹出 | map函数 | 子集求取 | 有序字符桶分装
  13. 【20保研】热忱欢迎全国2020届优秀本科毕业生免试攻读重庆大学研究生
  14. 【java校招你不知道的那些事儿】校招和社招的区别是什么?为什么不参加社招
  15. CPU结构及工作原理
  16. C语言中的strcat()函数
  17. linux 硬盘对拷,比ghost好用
  18. 抗氧化这题你会吗?别再只顾着入护肤品啦!!!
  19. 2020阿里前端岗暑期实习面试经历
  20. PS对图片进行透明化处理以及字体颜色的加深

热门文章

  1. 前端 table列表自行排序
  2. 论文翻译:Speech Super Resolution Generative Adversarial Network
  3. 美国大学排名之本科中最用功的学校top15
  4. LNMP架构和论坛搭建以及一键部署
  5. 天瑞地安科技集团程序员波波告诉你程序员必备开发工具
  6. OJ考试特别版,数组模拟链表(比正儿八经用链表简单,结果还对,何乐而不为)
  7. 常用的Python标准库有哪些
  8. RabbitMQ流量削峰应用
  9. HTML标记fort属性最大取值,CSS(2)---css字体、文本样式属性
  10. python3 class写法_Python抽象类的新写法