异常的处理
异常的概念
-
异常指的是在运行期间出现的错误,程序开始执行在执行期内出现的问题。出现了异常过后我们要关注异常的类型、异常出现的行号。
java的异常是java提供的用于处理程序错误的一种机制。错误是指程序运行过程中发生的一系列的异常事件,比如:下标越界、空指针、除数为0
异常处理机制:一旦异常发生过后,使用异常处理机制让程序不会直接中断或者直接影响虚拟机运行。
##异常的分类
- Error:称为错误,由java虚拟机生成并抛出,动态链接失败之类的错误等等,程序控制不了,用户也无法控制。jvm的环境问题,不属于异常
- Exception:用户的错误、或者程序无法预见的问题。是所有异常的父类,提供了很多的子类,每一种子类都对应到一种异常情况。一旦出现Exception这种异常,需要开发者自己去处理(捕获)。
- Runtime Exception:运行时异常是程序在运行过程中发生的,是可以被程序员避免的异常,如果说不处理,抛出异常过后,就提示开发人员关注这个异常。
常见的异常:
IOException IO异常
ClassNotFoundException
SQLException
NoSuchFieldException
RuntimeException
ClassCastException 类转换异常
NullPointerException 空指针异常
UnKnownTypeException
IndexOutofBoundsException 下标越界异常
ArithmeticException //数据异常
异常的执行流程
在方法执行中,方法押入到方法栈中,在某一个方法中出现了运行时异常,没有处理这种异常,后边方法的内容无法执行,异常抛给了虚拟机,中断了虚拟机运行。
方法栈:方法在调用的过程中,先执行方法然后退出
运行流程:
1.main在栈的最底部,method2的最顶部、method2抛出一个异常,method2从栈中取出来。
2.将异常抛给method1,method1并没有处理这个异常,将异常抛给main方法。此刻method1移除栈
3.main方法接收到method1抛出的异常,main也没有处理这个异常,当前这个异常就会抛给虚拟机,虚拟机就会创建一个异常对象,识别异常分类,直接将异常信息打印到控制台,结束程序。
异常的结构体系
Throwable
Error:表示错误,开发过程程序无法控制和处理
Exception:表示异常,在开发过程中可以处理
RuntimeException
SQLException
Exception:
检查异常:编译器要求必须要处理的异常,不处理程序无法运行。当你代码没有运行的时候,编译器就检查出来的问题。
非检查异常:编译器不强制要求处理的异常,虽然有可能在运行出问题,但是不要求你处理(主要指RuntimeException及其子类的异常)
异常的基本用法
捕获异常
语法1:
try{
程序在运行的过程中执行的逻辑代码,可能会出现问题
int res = 10/0;
}catch(Exception e){ //申明一个父类异常,接收任何一个异常,也可以接受一个具体的异常类型,但是异常类型必须匹配,只有当try出错才会运行catch
//提示当前系统出现了什么异常
System.out.println(“代码出错了”)
e.printStackTrace();(输出什么错)
}
try {
//运行过程中药执行的逻辑代码,这段代码可能会出现问题。捕获异常
int res = 10/0;
} catch (Exception e) { //声明一个父类异常,接收任何一个异常
//提示当前系统出现了什么样的异常
System.out.println(“代码出错了:”);
e.printStackTrace();
}
语法2:
try{
}catch(具体异常){
system.out.println(具体异常是什么)
}catch(具体异常或者Exception){
具体异常或其他异常
}
try {
int number = sc.nextInt();
result = 10/number;
} catch (InputMismatchException e) {
// 提示开发者操作程序出现异常
System.out.println("输入异常");
e.printStackTrace();
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("除数为0的异常");
} catch (Exception e3) {
// TODO: handle exception
System.out.println("有异常,但是不详!!");
}
语法3:
try{
}catch{
}finally{
}
try{
System.out.println("打开资源");
//将value的值存放到文件中 IO
System.out.println("打开文件,将value的值存放到文件");
/*String s = null;
System.out.println(s.toString());*/
}catch(Exception e){
System.out.println("操作文件的时候出现异常");
e.printStackTrace();
}finally{
System.out.println("关闭资源");
}
finally作用:
1.为异常提供了一个统一的出口,使得当前程序在跳转到另外程序的流程之前,能够对流程进行统一的管理。
2.无论try模块中的内容是否执行,finally代码都执行一次
3.通常我们在finally里面要执行的内容是资源关闭,或者日志的记录。
语法4:
try{
}finally{
隐藏异常,执行finally下的语句块
}
抛出异常
申明并抛出异常
在本方法中、如果出现了异常,本方法可以不进行处理,抛给调用者处理。
将异常异常一层一层的往外抛、在达到虚拟机之前处理好,整个程序运行流程也不受影响
throw:将异常进行抛出
throws:声明抛出何种类型的异常
public static void main(String[] args) {
System.out.println("(1)进入到main方法");
try {
method1();
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("(7)执行完了main方法");
}
public static void method1() throws Exception{
System.out.println("(2)进入到方法method1");
method2();
System.out.println("(6)执行完了method1");
}
public static void method2() throws Exception,FileNotFoundException{
System.out.println("(3)进入到方法method2");
System.out.println("(4)method2---execute");
try {
int i = 10/0;
} catch (Exception e) {
throw new Exception();
}
System.out.println("(5)执行完了method2");
}
自定义异常
重写方法的时候,子类和父类异常问题
1. 父类方法没有抛出异常,而子类重写的方法抛出了异常,是不允许的,编译通过不了
2. 父类抛出了异常,子类重写方法抛出跟父类方法同样的异常,没有问题
3. 父类抛出异常,子类重写方法不抛出运行,编译器编译能通过,但不推荐这样写
4. 父类抛出一个Exception,子类可以抛出比Exception小的异常,子类的异常不能比父类大
5. 父类抛出异常小于子类的异常,编译报错
6. 父类抛出一个Exception,子类抛出多个子异常,编译能通过
自定义异常
好处:
在团队开发过程中,都是分模块、分功能来进行开发的,在项目中统一制定自己的异常,对外统一显示内容
需要自定义的情况:
- 在用户发请求进行数据验证的时候,如果说数据验证失败,自己抛出自定义异常
- 在开发过程中,遇到某些逻辑上的问题,如判别性别出现中性的时候,java没有提供性别中性异常,自定义
- 系统提供的异常,如果直接给用户,体验不是特别好,包括异常的信息、代码、代码中能抛出去的异常,用户处理过的异常。
注:
1)不管是自定义异常还是系统提供的异常,都必须是Throwable的子类
2)写一个检查性的异常,需要写一个类继承Exception
3)写一些运行时异常,需要一个类继承RuntimeException