文章目录
- 异常概述
- 1.什么是异常?
- 2.为什么要异常?
- 异常体系及分类
- 1.运行时异常
- 2.编译时异常
- 异常处理
- 1.JVM默认处理方案
- 2.try…catch…
- 3.throw & throws
- (1)抛出异常throw
- (2)声明异常throws
- (3)throw和throws比较
- 自定义异常
- 1.自定义编译时异常
- 2.自定义运行时异常
- 异常的使用规则
异常概述
1.什么是异常?
异常是程序在“编译”或者“执行”的过程中可能出现的问题,(语法错误不算在异常体系中)
比如:数组索引越界、空指针异常、 日期格式化异常,等…
2.为什么要异常?
如果没有异常会怎么样?
- 无法穷举所有异常情况
- 错误处理代码和业务实现代码混杂
- 代码量增加
所以:
1.异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止.
2.避免异常,然后提前处理异常,体现的是程序的安全, 健壮性
异常处理机制:当程序运行出现意外情形时,系统会自动生成一个Exception对象来通知程序
异常体系及分类
异常体系如下图:
Error:
系统级别问题、JVM退出等,代码无法控制。
Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题
- RuntimeException及其子类:运行时异常,编译阶段不会报错。 (空指针异常,数组索引越界异常) ——程序员的主要关注点
- 除RuntimeException之外所有的异常:编译时异常,编译期必须处理的,否则程序不能通过编译。 (日期格式化异常)。
Throwable常用方法(一般用来返回异常信息):
1.运行时异常
直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误
常见运行时异常:
- 数组索引越界异常:ArraylndexOutOfBoundsException
- 空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
- 数学操作异常:ArithmeticException
- 类型转换异常:ClassCastException
- 数字转换异常: NumberFormatException
(一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误)
2.编译时异常
不是RuntimeException或者其子类的异常,编译阶就报错,必须处理,否则代码不通过
一般遇到情况 比较少,直接举个例子:
异常处理
1.JVM默认处理方案
如果程序出现了问题,我们没有做任何处理,最终JVM会做默认的处理
- 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
- 程序停止执行
缺点:直接从当前执行的异常点干掉当前程序。后续代码没有机会执行了,因为程序已经死亡
2.try…catch…
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。
格式:
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
}
执行流程:
1.程序从try里面的代码开始执行
2.出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统
3.当Java运行时系统接收到异常对象时,会到catch中去找匹配的异常类,找到后进行异常的处理执行完毕之后,程序还可以继续往下执行
3.throw & throws
(1)抛出异常throw
很多时候,在当调用方法使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。
具体操作:
-
创建一个异常对象。封装一些提示信息(信息可以自己编写)。
-
需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象。
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。语法:
throw new 异常类名(参数);
e.g.
public class ThrowDemo {
public static void main(String[] args) {
//创建一个数组
int[] arr = {2,4,52,2};
//根据索引找对应的元素
int index = 4;
int element = getElement(arr, index);
System.out.println(element);
System.out.println("over");
}
/*根据 索引找到数组中对应的元素*/
public static int getElement(int[] arr,int index){
//判断 索引是否越界
if(index<0 || index>arr.length-1){
/*
判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
*/
throw new ArrayIndexOutOfBoundsException("角标越界了```");
}
int element = arr[index];
return element;
}
}
注意主程序在getElement处异常就停止了,不会再输出后面的over语句。
(2)声明异常throws
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
抛出异常格式:
1.方法 throws 异常1,异常2,异常3 …{ }
2.方法 throws Exception{ }
(3)throw和throws比较
自定义异常
因为Java无法为这个世界上全部的问题提供异常类,所以某些时刻需要自定义异常
1.自定义编译时异常
定义一个异常类继承Exception.
重写构造器。
在出现异常的地方用throw new 自定义对象抛出
作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!
2.自定义运行时异常
定义一个异常类继承RuntimeException.
重写构造器。
在出现异常的地方用throw new 自定义对象抛出!
作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!
异常的使用规则
1.不要过度使用异常
- 把异常和错误混淆在一起,不编写任何错误处理代码,而是简单地抛出异常来代替所有错误处理
- 使用异常处理来代替流程控制
2.不要使用过于庞大的try块
try块过于庞大,难免后面会跟大量的catch块,此时需要分析他们之间的逻辑关系,反而导致了编程复杂度的增加
3.尽量提供对每个最小异常的处理
若每个异常都采用相同的处理方式,会导致无法对不通过异常分情况处理,以跟踪错误发生的原因
4.不要忽略捕获到的异常
在合适的层处理异常