项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步

1.异常分类

异常Exception是Java中非常常用的功能,它可以简化代码,并且增强代码的安全性。尤其是在各种服务相关的代码中,可能正常业务逻辑的代码量很少,大部分都是各种try catch处理各种异常的代码,因为实际中异常情况很多,为了保证服务的健壮与稳定性,要尽可能考虑与处理掉各种异常情况。所以在java中遇到大段大段的try catch也就不足为奇。


(图片来自网络)

从上面的图可以看出来,
1.Throwable是所有异常的根,java.lang.Throwable
2.Throwable包括Error与Exception两个子类。
3.Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。如java.lang.StackOverFlowError和Java.lang.OutOfMemoryError。对于这类错误,Java编译器不去检查他们,编译器也没法提前发现。对于这类错误导致的应用程序中断,仅仅靠程序本身是无法恢复与预防的。所以对于Error,一般是程序直接终止停止运行。
4.Exception类为程序可以处理的异常。遇到这种类型的异常,一般在代码中会去做相关处理,并且让程序恢复运行,而不是直接让程序终止运行。

2.Runtime Exception 与 Checked Exception

Runtime Exception一般表示虚拟机层面操作中可能遇到的异常,是一种常见运行时错误。运行时异常在代码中不一定要求捕获或者抛出。
常见的RuntimeException
1.NullPointerException NullPointerException是开发中最常见的UncheckedException,尤其实在代码调试阶段。如果在一个空指针上引用方法或变量或对象等,编译器编译的时候不会报错,但是运行期会抛出NullPointerException。
2.ArithmeticException 算术运算异常 最常见的为除数为0
3.IllegalArgumentException 传递非法参数异常
4. IndexOutOfBoundsException 下标越界异常 这个我们在处理各种数组,集合的时候也经常遇到。

Checked exceptions与runtime exception的目的不尽相同。Checked exception一般用来指示一种调用方能够直接处理的异常情况。而runtime exception一般是虚拟机层面的问题,代表一种调用方本身无法处理或恢复的程序错误。
checked exceptions意味着不在程序的即时控制内的错误场景。它们通常与外部资源/网络资源交互,例如数据库问题、网络连接错误、丢失文件等。程序中经常要处理各种资源文件,所以像FileNotFoundException这种异常就很常见。FileNotFoundException的继承关系如下图。

3.异常处理的基本方法

Java的异常处理本质上是抛出异常和捕获异常。
抛出异常:要理解抛出异常,首先要明白什么是异常情形(exception condition),它是指阻止当前方法或作用域继续执行的问题。其次把异常情形和普通问题相区分,普通问题是指在当前环境下能得到足够的信息,总能处理这个错误。对于异常情形,已经无法继续下去了,因为在当前环境下无法获得必要的信息来解决问题,你所能做的就是从当前环境中跳出,并把问题提交给上一级环境,这就是抛出异常时所发生的事情。抛出异常后,会有几件事随之发生。首先,是像创建普通的java对象一样将使用new在堆上创建一个异常对象;然后,当前的执行路径(已经无法继续下去了)被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方继续执行程序,这个恰当的地方就是异常处理程序或者异常处理器,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。
捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

对于运行时异常、错误和检查异常,Java技术所要求的异常处理方式有所不同。

由于运行时异常及其子类的不可查性,为了更合理、更容易地实现应用程序,Java规定,运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常。

对于方法运行中可能出现的Error,当运行方法不欲捕捉时,Java允许该方法不做任何抛出声明。因为,大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常。

对于所有的检查异常,Java规定:一个方法必须捕捉,或者声明抛出方法之外。也就是说,当一个方法选择不捕捉检查异常时,它必须声明将抛出异常。
(此部分内容来自参考文献1)

4.异常处理常见的样例

与异常处理相关的关键字有如下几个:try,catch,finally,throw,throws。所有异常的处理都围绕这几个字展开。
try: 用于监听,判断try代码块中的内容是否有异常。如果发生异常,将会被跑出来。
catch: 捕获try代码块中的相关异常。
finally: finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。比如关闭数据库连接、断开网络连接和关闭磁盘文件等。
throw: 用来抛出异常。
throws: 如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明,用在方法签名中。

4.1 try-catch方式捕获异常

这种是最常见的处理异常的方式。一般的用法如下:

try{//do something and might generate some exceptions
}catch(Exception e1){//handling exception1
}catch(Exception e2){//handling exception2
}

如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。
如果有多重catch,整体的原则为:先catch住子类,再catch父类,层层递进。

举个例子:

try{//code open a file
}catch(FileNotFoundException e1){//handling e1
}catch(IOException e2){//handling e2
}catch(Exception e3){//handling e3
}

4.2 try-catch-finally方式捕获异常

这种方式也很常见。与上面唯一的区别在于多了一个finally部分用来处理一些售后工作。

try{//code open a file
}catch(FileNotFoundException e1){//handling e1
}catch(IOException e2){//handling e2
}catch(Exception e3){//handling e3
}finally(){//close the file
}

4.3 方法中throw出异常

上面的方式,我们都是去捕获系统抛出的异常,当然我们也可以抛出来异常。在实际项目中,我们经常自己定义各种异常,方便快速定位与查找系统异常。
自己抛出异常也非常简单

throw ThrowableObject

只需要抛出一个Throwable的对象即可。比如我们经常用类似的方法这么做:

public class TestThrow extends Exception {public static class SomeException extends Exception {// nothing to do}public static void main(String[] args) {try {throw new SomeException();} catch (SomeException ex) {ex.printStackTrace();}}
}

先定义一个名为SomeException的类,该类继承自Exception。然后在逻辑中先抛出这个异常再catch住。
注意throw是在函数内。

4.4 throws

如果一个方法可以导致一个异常,但是在这个方法内我们不想处理,想交给他的调用者去处理,这个时候可以采用throws的方式。要做到这点,我们可以在方法声明中包含一个throws子句。一个throws子句列举了一个方法可能引发的所有异常类型,可以包括多个异常。

例如我们经常写的mapreduce程序里,mapper阶段的map方法就throws出来有两个异常:

  protected void map(KEYIN key, VALUEIN value, Context context) throws IOException, InterruptedException {context.write((KEYOUT) key, (VALUEOUT) value);}

所以我们每次重写map方法的时候,也会throws出这两个异常。
注意throws是在方法签名中,而不是在方法内部!

5.throw与throws的区别

throw语句在方法体内,标识抛出异常,有方法体内的语句来处理。一旦执行到throw语句,说明肯定要抛出异常,程序执行完throw语句之后立即停止;throw后面的任何语句不被执行,最邻近的try块用来检查它是否含有一个与异常类型匹配的catch语句。如果发现了匹配的块,控制转向该语句;如果没有发现,次包围的try块来检查,以此类推。如果没有发现匹配的catch块,默认异常处理程序中断程序的执行并且打印堆栈轨迹。
throws语句在方法签名中,主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。只是说该方法有可能要抛出某些异常。

6.finally中不要改变返回值

finally子句是可选项,可以有也可以没有。但是每个try语句至少需要一个catch或者finally子句。
如果try里面有个return语句,try 后的 finally{} 里的 code 会在方法返回调用者前被执行。
什么意思呢?总结起来一句话:在finally中改变返回值的做法是不好的。因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值。显然,在finally中返回或者修改返回值会对程序造成很大的困扰。
看两个例子:

public static int test() {int result = 0;try {result = 1;return result;} catch (Exception e) {result = 2;return result;} finally {result = 3;}
}

上面这段代码,方法的返回值是1。

public class TestFinally extends Exception {public static class Person {public String name;public Person(String name) {this.name = name;}}public static Person test() {Person person = new Person("lili");try {person.name = "mm";return person;} catch (Exception ex) {return person;} finally {person.name = "yy";}}public static void main(String[] args) {Person person = test();System.out.println(person.name);}
}

以上代码输出为yy!

如果finally中没有return语句,但是改变了要返回的值,这里有点类似与引用传递和值传递的区别,分以下两种情况,:

1)如果return的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值。

2)如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值。

不管怎么说,在finally中返回或者修改返回值都不是一件好事情,墙裂建议大家不这么干。

参考文献:
1.https://www.cnblogs.com/Qian123/p/5715402.html#_label2
2.https://blog.csdn.net/Next_Second/article/details/73090994

JAVA异常处理实战心得相关推荐

  1. Java异常学习心得

    2019独角兽企业重金招聘Python工程师标准>>> Java异常学习心得             本文重在Java中异常机制的一些概念.写本文的目的在于方便我很长时间后若是忘了这 ...

  2. java异常处理封装_Java统一异常处理(配置文件集中化定义)

    0.前言 无论任何项目,都避免不了在运行期间出现的一些异常,并伴随着因业务逻辑的需要而给出相应的提示,使得系统变得更加友好,这类提示处理,我们统称为异常处理(exceptiona handling). ...

  3. java课程设计心得体会绪论

      java课程设计心得体会绪论[篇1] 在上学期的最后一周和本学期的第一周,我和同组的学员在学校机房进行了JAVA暑期实训,现在已经结束了. 回首上学期的java学习,重点还是在学习概念等一些常识性 ...

  4. JAVA项目实战开发电商项目案例(十)订单与支付模块

    文章目录 1项目架构 2项目采用技术 3订单与支付模块功能演示 4如何开发支付宝的支付模块以及订单模块 4.1首先需要编写前端页面以及JS文件 4.2其次需要编写JAVA后台接口 4.3支付模块分析 ...

  5. java 语言 读书心得_深海夜未眠 小说java夜未眠读书心得

    <深海夜未眠 小说java夜未眠读书心得>由会员分享,可在线阅读,更多相关<深海夜未眠 小说java夜未眠读书心得(6页珍藏版)>请在人人文库网上搜索. 1.深海夜未眠 小说j ...

  6. Java EE学习心得

    –Java EE学习心得   1.    称为编程专家的秘诀是: 思考-----编程--------思考------编程--.. 编程不能一步到位,不能一上来就编,必须先思考如何写,怎样写?然后再编程 ...

  7. [零基础学JAVA]Java SE实战开发-37.MIS信息管理系统实战开发[JDBC](1)

    MIS信息管理系统实战开发之使用MySQL实现保存 开发背景 ID.姓名.年龄为公共信息,而学生有成绩,工人有工资 定义一个抽象类Person(ID.姓名.年龄),学生是其子类,有成绩,工人是其子类有 ...

  8. Java异常处理12条军规

    摘要: 简单实用的建议. 原文:Java异常处理12条军规 公众号:Spring源码解析 Fundebug经授权转载,版权归原作者所有. 在Java语言中,异常从使用方式上可以分为两大类: Check ...

  9. Java 异常处理的 9 个最佳实践

    Java 异常处理的 9 个最佳实践 原文地址:https://dzone.com/articles/9-... 翻译出处:https://www.oschina.net/trans... 在 Jav ...

  10. 《转载》Java异常处理的10个最佳实践

    本文转载自 ImportNew - 挖坑的张师傅 异常处理在编写健壮的 Java 应用中扮演着非常重要的角色.异常处理并不是功能性需求,它需要优雅地处理任何错误情况,比如资源不可用.非法的输入.nul ...

最新文章

  1. 【AJAX】DWR入门教程
  2. 业界首个机密计算容器运行时—Inclavare Containers正式进入CNCF!
  3. 通过Playbook部署LAMP(5)
  4. idea新建springboot后端到前端_基于SpringBoot+AntDesign的快速开发平台
  5. input输入格式转换插件-Vanilla Masker
  6. 《一》Android 数据库 SQlite SQLiteOpenHelper
  7. IDL编程实现拟合树的圆心代码
  8. oracle热点表online rename
  9. asmack获取用户头像和设置昵称与获取好友昵称
  10. 【71】力科PCIe 协议分析仪常见操作
  11. python视频换脸下载_FaceSwap下载|Faceswap(AI视频换脸软件) v1.0官方版(附使用教程)...
  12. 在Word中,如何删除页眉页脚
  13. MVC5+EF6 入门完整教程
  14. HBuilderX 打包问题
  15. Kafka High Level API vs. Low Level API
  16. 从原理到实现 | 如何通过球面投影将点云转换为Range图像
  17. 【weJudge】1106. [ACM][2014新生赛重现][现场]Gundam Unicorn
  18. 妙用“Check out”与“Check In”
  19. Dialer 联系人加载
  20. 警惕Pycharm命名问题

热门文章

  1. Flask模板操作一:基本使用
  2. Java 容器源码分析之 ArrayList
  3. 请详细描述LVS DR模式的原理
  4. JVM 基础知识(GC)
  5. DEV控件之ChartControl用法
  6. cacti 安装部署
  7. 深度学习在图像分类中的应用
  8. js中的~~、Object.entires用法(转)
  9. 近乎 5.3 发布,SNS 社区系统
  10. 【Java基本功】很多人经常忽视的Java基础知识点