java 自定义异常_Java基础系列(1)小白也能看懂的的Java异常处理

4c061ee10acb267443d72dfb51390211.png

不积跬步,无以至千里;不积小流,无以成江海

什么是异常处理机制?

异常处理机制就是当程序发送异常时,它强制终止程序运行,记录异常信息并将这些信息反馈给我们,由我们来确定处理异常

异常的分类

efb9ec16ec41a55a9816eede618b7c60.png

7f7974f0928567b793c481a4f583b1fb.png

Exception 和 Error的区别是什么?

Exception 和 Error 都是继承了 Throwable 类,在 Java 中只有 Throwable 类型的实例才可以 被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。

Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。

Error 是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比 如 OutOfMemoryError 之类,都是 Error 的子类。

总结:

  • Throwable是java语言中所有错误和异常的超类
  • Throwable又派生出Error类和Exception类

ERROR:错误:

  • Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。

Exception:异常

Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。

异常两大类

  • 非检查异常
    • Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try…catch…finally),这样的异常,也可以不处理。
    • 对于这些异常,我们应该修正代码,而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
  • 检查异常
    • 除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。

初识异常

  • 异常是在执行某个函数时引发的,而函数又是层级调用,形成调用栈的,因此,只要一个函数发生了异常,那么他的所有的caller都会被异常影响。当这些被影响的函数以异常信息输出时,就形成的了异常追踪栈。
  • 异常最先发生的地方,叫做异常抛出点。

异常的基本处理方式

  • 使用try…catch…finally语句块处理它
  • 在函数签名中使用throws 声明交给函数调用者caller去解决
  • 自动抛出,让框架的异常捕获处理

纠结的Finally

  • finally块不管异常是否发生,只要对应的try执行了,则它一定也执行。只有一种方法让finally块不执行:System.exit()。因此finally块通常用来做资源释放操作:关闭文件,关闭数据库连接等等。
  • 良好的编程习惯是:在try块中打开资源,在finally块中清理释放这些资源。

Finally需要注意的地方

  1. finally块没有处理异常的能力。处理异常的只能是catch块
  2. 在同一try…catch…finally块中 ,如果try中抛出异常,且有匹配的catch块,则先执行catch块,再执行finally块。如果没有catch块匹配,则先执行finally,然后去外面的调用者中寻找合适的catch块。
  3. 在同一try…catch…finally块中 ,try发生异常,且匹配的catch块中处理异常时也抛出异常,那么后面的finally也会执行:首先执行finally块,然后去外围调用者中寻找合适的catch块。

总结:

正常情况下,finally块里代码都会被执行,除非一种特殊情况,在try或者catch中强行调用System.exit(0);

异常调用链

异常链化:以一个异常对象为参数构造新的异常对象,新的异常对象将包含先前的异常信息。这项技术主要是异常类的一个带Throwable参数的函数来实现的,这个当做参数的异常,我们叫根源异常

通过查看Throwable类源码,可以发现里面有一个Throwable字段cause,就是它保存了构造时传递的根源异常参数。这种设计和链表的结点类设计如出一辙,因此形成链也是自然的了。

自定义异常

如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。

如何自定义一个异常

  1. 一个无参的构造函数
  2. 一个带有String参数的构造函数,并传递给父类的构造函数
  3. 一个带有String参数和Throwable参数,并都传递给父类构造函数
  4. 一个带有Throwable参数的构造函数,并传递给父类的构造函数
public 

异常注意事项

1、当子类重写父类的带有 throws声明的函数时,其throws声明的异常必须在父类异常的可控范围内——用于处理父类的throws方法的异常处理器,必须也适用于子类的这个带throws方法 。这是为了支持多态。

例如,父类方法throws 的是2个异常,子类就不能throws 3个及以上的异常。父类throws IOException,子类就必须throws IOException或者IOException的子类。

2、Java的异常执行流程是线程独立的,线程之间没有影响

Java程序可以是多线程的。每一个线程都是一个独立的执行流,独立的函数调用栈。如果程序只有一个线程,那么没有被任何代码处理的异常 会导致程序终止。如果是多线程的,那么没有被任何代码处理的异常仅仅会导致异常所在的线程结束。

当finally遇上return

在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。

  • finally中的return 会覆盖 try 或者catch中的返回值。
  • finally中的return会抑制(消灭)前面try或者catch块中的异常
  • finally中的异常会覆盖(消灭)前面try或者catch中的异常

友好建议

  • 不要在fianlly中使用return。
  • 不要在finally中抛出异常。
  • 减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。
  • 将尽量将所有的return写在函数的最后面,而不是try … catch … finally中。

Java异常常见面试题

1. Java中什么是Exception(菜鸟级别问题)

异常是Java传达给你的系统和程序错误的方式。在java中,异常功能是通过实现比如Throwable,Exception,RuntimeException之类的类,然后还有一些处理异常时候的关键字,比如throw,throws,try,catch,finally之类的。 所有的异常都是通过Throwable衍生出来的。Throwable把错误进一步划分为 java.lang.Exception 和 java.lang.Error. java.lang.Error 用来处理系统错误,例如java.lang.StackOverFlowError 之类的。然后 Exception用来处理程序错误,请求的资源不可用等等

2. Java中的检查型异常和非检查型异常有什么区别?(流行)

  • 检查型异常和非检查型异常的主要区别在于其处理方式。检查型异常需要使用try, catch和finally关键字在编译期进行处理,否则会出现编译器会报错。对于非检查型异常则不需要这样做。Java中所有继承自java.lang.Exception类的异常都是检查型异常,所有继承自RuntimeException的异常都被称为非检查型异常。

3.Java中的NullPointerException和ArrayIndexOutOfBoundException之间有什么相同之处?

  • 这两个异常都是非检查型异常,都继承自RuntimeException。该问题可能会引出另一个问题,即Java和C的数组有什么不同之处,因为C里面的数组是没有大小限制的,绝对不会抛出

4. 在Java异常处理的过程中,你遵循的那些最好的实践是什么?

  • 调用方法的时候返回布尔值来代替返回null,这样可以避免空指针异常( NullPointerException)。由于空指针是java异常里最恶心的异常catch块里别不写代码。空catch块是异常处理里的错误事件,因为它只是捕获了异常,却没有任何处理或者提示。通常你起码要打印出异常信息,当然你最好根据需求对异常信息进行处理。
  • 能抛受控异常(checked Exception)就尽量不抛非控异常(checked Exception)。通过去掉重复的异常处理代码,可以提高代码的可读性。
  • 绝对不要让你的数据库相关异常显示到客户端。由于绝大多数数据库和SQLException异常都是受控异常,在Java中,你应该在DAO层把异常信息处理,然后返回处理过的能让用户看懂并根据异常提示信息改正操作的异常信息。
  • 在Java中,一定要在数据库连接,数据库查询,流处理后,在finally块中调用close()方法

5. 既然我们可以用RuntimeException来处理错误,那么你认为为什么Java中还存在检查型异常?

  • 存在检查型异常是一个设计上的决定,受到了诸如C++等比Java更早编程语言设计经验的影响。绝大多数检查型异常位于http://java.io包内,这是合乎情理的,因为在你请求了不存在的系统资源的时候,一段强壮的程序必须能够优雅的处理这种情况。通过把IOException声明为检查型异常,Java 确保了你能够优雅的对异常进行处理。另一个可能的理由是,可以使用catch或finally来确保数量受限的系统资源(比如文件描述符)在你使用后尽早得到释放

6.throw 和 throws这两个关键字在java中有什么不同?

  • throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常, 你也可以申明未检查的异常,但这不是编译器强制的。如果方法抛出了异常那么调用这个方法的时候就需要将这个异常处理。另一个关键字 throw 是用来抛出任意异常的,按照语法你可以抛出任意 Throwable (i.e. Throwable 或任何Throwable的衍生类) , throw可以中断程序运行,因此可以用来代替return . 最常见的例子是用 throw 在一个空方法中需要return的地方抛出 UnSupportedOperationException

7. 什么是“异常链”?

  • “异常链”是指在进行一个异常处理时抛出了另外一个异常,由此产生了一个异常链条。该技术大多用于将“ 受检查异常” ( checked exception)封装成为“非受检查异常”(unchecked exception)或者RuntimeException。顺便说一下,如果因为异常你决定抛出一个新的异常,你一定要包含原有的异常,这样,处理程序才可以通过getCause()和initCause()方法来访问异常最终的根源。

8. JDK7中对异常处理做了什么改变?

  • JDK7中对错误(Error)和异常(Exception)处理主要新增加了2个特性,一是在一个catch块中可以出来多个异常,就像原来用多个catch块一样。另一个是自动化资源管理(ARM), 也称为try-with-resource块。这2个特性都可以在处理异常时减少代码量,同时提高代码的可读性

9. 如果执行finally代码块之前方法返回了结果,或者JVM退出了,finally块中的代码还会执行吗?

  • 如果在try或者catch的代码块中调用了System.exit(0),finally代码块的代码不会执行,
  • 如果是在try里或者catch代码块里使用return返回了结果,finally的代码块仍会执行,且finally的return结果会覆盖try和catch代码块的return结果

10. Java中final,finalize,finally关键字的区别

  • final和finally是Java的关键字,而finalize则是方法。final关键字在创建不可变的类的时候非常有用,只是声明这个类是final的。而finalize()方法则是垃圾回收器在回收一个对象前调用,但是Java规范里面没有保证这个方法一定会被调用。finally关键字是唯一 一个和这篇文章讨论到的异常处理相关的关键字。在你的产品代码中,在关闭连接和资源文件的是时候都必须要用到finally块。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值