一. 异常概念与体系结构:
1 异常的概念:在 Java 中,将程序执行过程中发生的 不正常行为 称为异常,
如:算数异常: ArithmeticException
代码语言:javascript复制System.out.println(10 / 0);
// 执行结果
Exception in thread "main" java.lang.ArithmeticException: / by zero
数组越界异常:ArrayIndexOutOfBoundsException
代码语言:javascript复制int[] arr = {1, 2, 3};
System.out.println(arr[100]);
// 执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
空指针异常: NullPointerException
代码语言:javascript复制int[] arr = null;
System.out.println(arr.length);
// 执行结果
Exception in thread "main" java.lang.NullPointerException
2.异常的体系结构:异常种类繁多,为了对不同异常或者错误进行很好的分类管理, Java 内部维护了一个 异常的体系结构 如图:
从图中可以看出:
(1).Throwable : 是异常体系的顶层类,其派生出两个重要的子类, Error 和 Exception
(2). Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表: StackOverflowError和OutOfMemoryError,一旦发生回力乏术。
(3).Exception : 异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说的异常就是Exception。
OutOfMemoryError为内存泄漏 :程序中存在未释放的内存资源,导致内存占用不断增加,最终导致内存不足等等
StackOverflowError为:无限递归下去导致, 超出栈的容量等等
3. 异常的分类:分为 编译时异常, 运行时异常。
(1). 编译时异常: 在程序 编译期间 发生的异常,称为 编译时异常 ,也称为 受检查异常
如图:这个重写,克隆方法的拷贝,没有对其捕获或声明
下图则是声明: 就编译通过
2. 运行时异常:
(1) 在程序 执行期间 发生的异常,称为运行时异常,也称为 非受检查异常
(2)RunTimeException以及其子类对应的异常,都称为运行时异常。
比如NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException。
注意:编译时出现的语法性错误,不能称之为异常。例如将 System.out.println 拼写错了, 写成了
这里也用克隆举例子,这里没有实现克隆接口,却编译通过了!!!
但是运行会有异常:这就是非受查异常
二. 异常的处理:
在Java中, 异常处理主要的 5 个关键字: throw 、 try 、 catch 、 final 、 throws 。用好他们就,可以很好的处理异常了。
1. 异常的抛出 :在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者
注意:
(1). throw必须写在方法体内部
(2). 抛出的对象必须是Exception 或者 Exception 的子类对象
(3). 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
(4). 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
(5). 异常一旦抛出, 其后 的代码就不会执行。
如图:这里还用了,try处理catch捕捉
代码语言:javascript复制public static void main(String[] args)throws ArrayIndexOutOfBoundsException {
int[] array = new int[2];
//捕捉异常
try {
//放可能发生的异常
System.out.println(array[3]);
System.out.println("这里不会再执行了");
}catch (ArrayIndexOutOfBoundsException e) {
//捕捉异常
System.out.println("处理了ArrayIndexOutOfBoundsException异常");
//捕捉,打印异常
e.printStackTrace();
}
}
2.异常的捕获:异常的捕获,也就是异常的具体处理方式,主要有两种: 异常声明throws 以及 try-catch捕获处理。
抛出异常:
代码语言:javascript复制public static void OpenConfig(String filename) throws FileNotFoundException {
if (filename.equals("config.ini")) {
throw new FileNotFoundException("配置文件名字不对");
}
}
3.try-catch 捕获并处理 :throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch。)
此时声明一下,然后捕获:( 直接声明不捕获也可以 )
代码语言:javascript复制class Exception {
File file;
/*
FileNotFoundException : 编译时异常,表明文件不存在
此处不处理,也没有能力处理,应该将错误信息报告给调用者,让调用者检查文件名字是否给错误了
*/
public static void OpenConfig(String filename) throws FileNotFoundException {
if (filename.equals("config.ini")) {
throw new FileNotFoundException("配置文件名字不对");
}
}
//捕获
public static void main(String[] args) {
try {
//将可能出现异常的代码放在这里
OpenConfig("test");
} catch (FileNotFoundException e) {
// 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时,或者是try中抛出异常的基就会时,就会被捕获到
e.printStackTrace();
}finally {
// 此处代码一定会被执行到,一般用来关闭文件,释放资源
}
}
}
注意:1.try块内抛出异常位置之后的代码将不会被执行。
2. 如果 抛出异常类型与catch时异常类型不匹配 ,即异常不会被成功捕获,也就不会被处理,继续往外抛 ,直到 JVM收到后中断程序。 (一般写法是,用父类异常在最后面兜底)
4.finally:
在写程序时, 有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源 :网络连接、数据库连接、IO 流等, 在程序正常或者异常退出时,必须要对资源进进行回收 。另外,因为 异常会引发程序的跳转,可能导致有些语句执行不到 , finally 就是用来解决这个问题的。
还有 finally 中的代码一定会执行的,一般在 finally 中进行一些资源清理的扫尾工作
代码语言:javascript复制语法格式:
try{
// 可能会发生异常的代码
}catch(异常类型 e){
// 对捕获到的异常进行处理
}finally{
// 此处的语句无论是否发生异常,都会被执行到
}
// 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行
(补充)异常的处理流程: 如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递 ( 方法1--》方法2--》方法3---》main方法----》jvm)
三. 自定义异常类:
Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我们实际情况的异常结构.就需要自定义异常
例如, 我们实现一个用户登陆功能:
根据业务此时我们在处理用户名密码错误的时候可能就需要抛出两种异常
注意:
1.自定义异常类,然后继承自Exception 或者 RunTimeException
2. 实现一个带有String类型参数的构造方法,参数含义:出现异常的原因
业务代码:
代码语言:javascript复制class login {
private String userName;
private String passWord;
public void loginFo(String userName, String passWord)throws UserException,PassWardException{
if (!this.userName.equals(userName)) {
throw new UserException("抛出自定义,的用户名错误异常");
}
if (!this.passWord.equals(passWord)) {
throw new PassWardException("抛出密码自定义,的用密码错误异常");
}
System.out.println("登录成功!");
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
}
public class TestException {
public static void main(String[] args) throws UserException {
login login = new login();
login.setPassWord("321");
login.setUserName("haha");
login.loginFo("haha", "323");
/*try {
login.loginFo("haha", "323");
}catch (UserException e) {
e.printStackTrace();
}catch (PassWardException e) {
e.printStackTrace();
}finally {
}*/
}
}