异常处理
1 概述:
在Java语言中,将程序执行中发生的不正常情况称为”异常“。(开发过程中的语法错误和逻辑错误不是异常)
2 异常的分类:
- Error:
- Java虚拟机出现无法解决的严重问题,程序员无法解决,重启即可
- Exception:
- 因为编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理
3 异常的体系结构:
- java.lang.Throwable
- java.lang.Error
- java.lang.Exception
- 编译时异常(checked)
- IOException
- FileNotFoundException
- ClassNotFoundException
- IOException
- 运行时异常(unchecked)
- NullPointerException
- ArrayIndexOutOfBoundsException
- ClassCastException
- NumberFormatException
- InputMismatchException
- ArithmeticException
- 编译时异常(checked)
- 异常的体现非常多,远不止以上这些
4 异常处理
java提供的是异常处理的抓抛模型。
- 过程一:”抛“:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出,一旦抛出对象以后,其后的代码就不再执行。
- 关于异常对象的产生:
- 1.系统自动生成的异常对象
- 2.手动的生成一个异常对象,并抛出(throw)
- 关于异常对象的产生:
- 过程二:”抓“:可以理解为异常处理的方式:1.try-catch-finally 2.throws
异常处理的体会
- 体会1:使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现
- 体会2:开发中,由于运行时异常比较常见,所有我们通常就不针对运行时异常编写try-catch-finally了。针对编译时异常,我们说一定要考虑异常的处理。
- 体会3:
- try-catch-finally:真正的将异常给处理掉了
- throws 的方式只是将异常异常抛给了方法的调用者。并没有真正的将异常处理掉
5 异常处理的机制一:try-catch-finally
结构:
try{
// 可能出现异常的代码
}catch(异常类型1 变量1){
// 处理异常的方式1
}catch(异常类型2 变量2){
// 处理异常的方式2
}catch(异常类型3 变量3){
// 处理异常的方式3
}
......
finally{
// 一定会执行的代码
}
常用的异常对象的处理方法:
- String getMessage();
- printStackTrace(); (比较常用)
注意事项:
- finally是可选的
- finally中声明的是一定会被执行的代码,即使是catch中又出现异常了、try中有return语句、catch中有return语句等情况
- finally一般什么时候用?
- 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。
6 异常处理的机制二:throws
格式:throws+异常类型 (放在在方法什么的()后面)
“throws+异常类型” 写在方法的声明处,指明此方法执行时,可能会抛出的异常类型。一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会抛出。异常代码后续的代码就不再执行。
class Test{
public void test () throws ArrayIndexOutOfBoundsException{
int[] arry = new int[9];
System.out.println(arry[9]);
}
}
含有throws语句的方法被重写规则:
规则一:子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型。
规则二:由规则一可以知道,父类的方法有异常,子类重写的方法可以不抛出异常。
规则二:由规则一可以知道,父类的方法如果没有抛出异常,则子类一定不可以抛出异常。
7 开发中如何选择try-catch-finally和throws
- 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally的方式处理
- 执行的方法 a 中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法都使用throws的方式进行处理。而执行的方法 a 可以考虑使用 try-catch-finally 的方式进行处理。
8 手动抛出异常
格式:throw new 异常类名(“报错信息”);
class Student{
private int id;
public int getId() {
if (id==0){
// 运行时异常,可以不处理
throw new RuntimeException("当前没有对id赋值");
}
return id;
}
public void setId(int id) throws Exception {
if (id>0){
this.id = id;
}else {
// 异常,包括编译时异常,需要处理
throw new Exception("您输入的数据非法!");
}
}
}
class Test{
public static void main(String[] args){
Student student=new Student();
// student.getId(); // 报错,因为我们手动抛出了一个异常(如果id没有赋值)
// 需要try-catch处理异常,因为我们抛出的时Exception异常,这个异常包括了编译时异常
try{
student.setId(3);
}catch(Exception e){
e.printStackTrace();
}
System.out.println(student.getId());
}
}
9 用户自定义异常
如何自定义异常类?
- 1.继承于现有的异常结构:RuntimeException、Exception
- 继承 RuntimeExcetion 与 Exception 的区别
- 继承 RuntimeExcetion 不需要显式的处理异常
- 继承 Exception 需要显式的处理异常
- 即方法里创建了异常类后,方法声明处需不需要 throws
- 继承 RuntimeExcetion 与 Exception 的区别
- 2.提供全局常量:serialVersionUID
- 3.提供重载的构造器
class MyException extends Exception{
static final long serialVersionUID = -3387516343124225948L;
public MyException() {
}
public MyException(String message) {
super(message);
}
}