本篇文章将会对Java中关于异常的相关知识进行总结,主要包括以下内容:
- 什么是异常
- 异常处理的两种方式
- 手动抛出异常
- 如何自定义异常
什么是异常
在一个软件的使用过程中,有许多不确定的因素会导致程序出现问题,例如:程序需要用户输入一个数字,但是用户可能会输入一个字符;程序需要打开一个文件,但是确不能确保文件存在。这些不确定因素导致的程序出现问题的错误,就称之为异常。
通常情况下,一个在设计一个程序是,需要考虑到以下的问题:
- 用户输入。虽然在程序设计时会明确的告诉用户输入什么内容,但是也一定会有用户会输入错误的格式。
- 设备错误。硬件可能会由于各种原因导致无法正常被使用,例如打印机在打印时没纸了。
- 物理限制。例如用户的电脑磁盘空间已满。
- 代码错误。程序方式是否可能会出现错误。例如一个方法可能返回一个错误的答案,无效的数组索引等。
异常不是一定会发生的,而是可能会发生的。
Java中所有的异常都派生于Throwable类,在其下一层又分为两类异常,: - Error:Java虚拟机无法解决的严重问题,如StackOverflowError,无法通过编写针对性的代码处理。
- Exception:其他因编程错误或偶然外因导致的一般性错误。可以使用针对性的代码进行处理。
在实际编程中,我们主要时对Exception异常做出处理。在Exception异常中又可以笼统的非为受检异常和非受检异常:
- 受检异常:这类异常是由一些外部的偶然因素所引起的,所以这类异常通常需要进行进行处理,例如IOException。
- 非受检异常(运行时异常):这类异常是编程人员的逻辑问题。属于程序设计上的错误,例如IndexOutOfBoundsException(下标越界错误),这些错误是程序员在设计时就需要考虑到的错误。Java编译器不进行强制要求处理,即在编译时不会报错,但是运行时会。

异常处理
Java中异常处理可以分为两个过程:
抛出异常
过程一:抛出异常(Throws),方法在正常执行的过程中,一旦出现异常,就会在异常代码出生成一个对应异常类的对象,并将此对象抛出。异常可以被一层一层的抛,一直抛到main方法。一旦抛出异常以后,其后的代码就不再执行。且一个方法可以允许抛出多个异常,但是每次自会抛出一个异常。
子类重写的方法抛出异常类型不大于父类被重写的方法抛出的异常,如果父类没有抛出异常,则子类重写的方法也不能抛出异常
1 | public class ExceptionTest3 { |
上面的代码中method1方法可能会抛出FileNotFoundException或者IOException异常(FileNotFoundException是IOException的一个子类),抛出的异常将会传给method2方法,然后method2方法再抛出一个IOException方法,最后method3方法对这个异常进行了捕获和处理。
子类重写的方法抛出异常类型不大于父类被重写的方法抛出的异常,如果父类没有抛出异常,则子类重写的方法也不能抛出异常。
1 | class SuperClass{ |
捕获异常
捕获异常的代码格式大致如下:
1 | try{可能出现异常的代码 |
其语法的意思是:
- 使用try将可能出现异常代码包装起来,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配
- 一旦try中的异常对象匹配到某一个 catch时,就进入 catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没有写finally的前提下),继续执行其后的代码
需要注意的是:catch中的异常类型如果有子父类关系,则要求子类一定要声明在父类的上面,否则报错。在try结构中声明的变量,在try结构之外将不能够调用.
1 | public void test2() { |
这里有两个常用的异常对象处理方式:String getMessage():打印异常信息.
printStackTrace():打印整个堆栈的信息
try - catch-finally结构式可以嵌套使用的
1 | public void test2() { |
对于finally来说,是一个可选一个环节,finally中声明的是一定会被执行的代码。即使 catch中又出现异常了,try中有 return语句, catch中有return语句等情况,像数据库连接、输入输出流、网络編程 Socket等资源,JWM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中.例如上面的实例程序中就将关闭文章的代码放在了finally结构中,确保如果文件以打开,但是发生了异常,该文件能够被关闭.
手动抛出异常
以上的方式都是系统自东生成的异常,只有再系统规定的情况下才会抛出。但是有些时候我们希望再不满足我们自己设计的要求是也会报错,比如我们需要用户输入一个正数时,用户输入负数的时候我们就希望能够出现一个异常。
这是我们就希望能够自己设定一个条件,再满足这个条件时抛出一个指定的异常。
1 | public static void main(String[] args) { |
上面的示例中,就通过throw手动的创建了一个异常对象,当用户输入负数时会抛出,然后在方法的调用出将会得到处理。
throws体现的异常的处理,将会抛出一个异常,用于方法的声明处。
throw是生成一个异常对象,是在方法内。
自定义异常类
手动抛出一个异常,依然只能抛处一个系统已经定义了的异常类型,有时候我们更希望能够自己定义一个异常类型,来更好的说明自己当前项目中可能出现的异常。
自定义异常类中通常会包含三个部分:
- 继承于现有的异常结构:RuntimeException、Exception
- 提供全局常量:serialVersionUID,用于位于标识这个类
- 提供重载的构造器,一个无参构造器,和一个包含详细描述异常信息的构造器
1 | public class MyException extends RuntimeException{ |
该例中就创建了一个继承于RuntimeException类的异常类,该类中有一个erialVersionUID常量,用于作为该类的唯一标识,以及一个无参构造器,和一个有参构造器,该构造器又调用了其父类的构造器。
下面使用以下这个构造器:
1 | public class Person { |
这里就是使用了自定义的异常类。
本文链接: https://quandongli.github.io/post/fbeade06.html
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
