1、异常概念
指程序在执行过程中出现的非正常情况,会导致JVM的非正常停止,
异常本来是一个类,产生异常就是创建异常对象并抛出。
2、异常体系
最高父类throwable,子类error和exception
3、异常分类
运行期异常、编译期异常和错误
运行期异常可以不处理,默认让JVM终止程序
编译期异常必须处理
错误无法解决,必须修改代码
4、throw/throws关键字
异常处理常用到5个关键字
try
catch
finally
throw
throws
其中,throw关键字用于抛出异常(在方法内使用)
即方法内某语句可能异常时使用,可以把异常抛出给方法
方法在定义时要使用throws关键字接受方法内抛出的异常并再次抛出给方法调用者。
同理,如果是多级调用,每一级都要使用throws关键字接受并上抛(或者try/catch处理),最终抛出给main方法,在由main方法抛给jvm,最后中断程序。
注意:如果throw声明的方式运行期异常,可以不用throws上抛
private static int getElement(int[] arr,int index) {
if(arr == null){
throw new NullPointerException("传递的数组为空");
}
if(index<0 || index>arr.length-1){
throw new ArrayIndexOutOfBoundsException("索引越界");
}
int ele = arr[index];
return ele;
}
如上,是执行参数合法性验证的代码,如果参数不符合要求,就会抛出空指针异常,但空指针异常时运行期异常,因此方法中不用使用throws关键字
5、Object非空判断
Object类中有一个方法可以很好的完成对参数是否为空的判断
public static <T> T rquireNonNull(T obj)//查看指定引用对象是不是null
//可以传递第二个参数,来实现异常触发时打印自定义的消息
示例:
public static void method(Object obj){
//对传递进来的参数进行合法性判断,判断是否为null
// if(obj==null){
// throw new NullPointerException("空指针");
//
// }
//Objects.requireNonNull(obj);
Objects.requireNonNull(obj,"空指针");
}
注释中的代码与第八行的代码等效
6、异常处理的第一种方法,throws
前文说过,throws可以把异常交给调用者,这即是异常处理的第一种方法,交给别人处理
格式:
修饰符 返回值 方法名(形参表) throws XXXException{
throw new XXXException("触发时四处的字符串");
}
即方法中声明一个Exception异常,方法声明是就要加上这个异常(方法内声明多个,throws也要声明多个)
注意:
1、声明的对象必须是Exception或其子类
2、如果抛出的多个异常中有继承关系,声明父类即可
3、调用了声明抛出异常的方法就必须处理
public static void reader(String filename) throws IOException {
if (!filename.equals("c:\\\\a.txt")){
throw new FileNotFoundException("找不到文件");
}
/**
* 如果不是.txt结尾
* 那么抛出IO异常对象
*/
if (!filename.endsWith(".txt")){
throw new IOException("文件类型错误");
}
System.out.println("没有问题");
}
注意:main方法调用时也要处理异常,throws抛给虚拟机或者try/catch处理
7、异常处理的第二种方法、try/catch
try/catch可以捕获并处理异常
格式:
try{
//可能出现异常的代码
}catch(定义代码变量 用来接收异常){
//处理异常的代码
}
try中代码如果出现异常就会执行catch中的代码并继续执行程序。
public static void main(String[] args) {
try {
reader("d:\\a.tx");
}catch (IOException e){//抛出什么异常,就定义什么异常
System.out.println(e);
}
}
public static void reader(String filename) throws IOException {
if (!filename.endsWith(".txt")){
throw new IOException("找不到文件");
}
System.out.println("没有问题");
}
上面的代码,在reader方法中使用throws抛出方法,在main方法中捕获并处理,处理方法是打印该异常的信息
8、throwable类中的三种处理方法
/**
* throwable类中定义了三个处理异常的方法
* String toString() 返回此throwable的简短描述
* String getMessage() 返回此throwable的详细消息字符串
* String printStackTrace() JVM打印异常对象调用此方法,信息最全面
*
*/
9、finally关键字
finally关键字和try/catch一起使用,finally代码块中的代码无论异常时候发生都会被执行。
格式:
try{
可能异常的代码
}catch{
异常处理
}finally{
无论是否出现异常,都会执行
}
注意:
1、finally关键字不能单独用
2、finally一般用于资源回收
3、别再finally里写return,否则返回值就是finally里的内容
10、多异常捕获与处理
有三种处理思路
10.1、多个异常分别处理
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e);
}
即一个一个捕获和处理异常
10.2、多异常一次捕获,多次处理
即一次捕获所有异常,再挨个处理
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.get(3));
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e);
}catch (IndexOutOfBoundsException e){
System.out.println(e);
}
try中代码会产生两个异常,分别用两个catch处理
注意:多个catch中的异常对象如果有继承关系,子类一定要写上面
10.3、多异常一次捕获一次处理
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list.get(3));
}catch (IndexOutOfBoundsException e){
System.out.println(e);
}
System.out.println("后续代码");
一次捕获所有异常,再一次全部处理
11、父子类的异常
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或是父类异常的子类或者不抛出
父类方法没有抛出异常,子类重写父类该方法时也不可能抛出异常,此时子类产生该异常,只能捕获,不能声明抛出
即父类的异常什么样,子类的异常就声明样
public class ZiFuExceptionDemo {
public void show01() throws NullPointerException,ClassCastException{ }
public void show02() throws IndexOutOfBoundsException{ }
public void show03() throws IndexOutOfBoundsException{ }
public void show04(){ }
}
class Zi extends ZiFuExceptionDemo{
//子类重写父类方法时,抛出和父类相同的异常
public void show01() throws NullPointerException,ClassCastException{ }
//子类重写父类方法时,抛出父类异常的子类
public void show02() throws ArrayIndexOutOfBoundsException{}
//子类重写父类方法时,可以不抛出
public void show03(){}
//父类没抛异常,子类也不能抛,只能捕获
public void show04(){}
}
12、自定义异常
自定义异常类供某些情况下使用
格式:
public class XXXException extends Exception/RuntimeException{
添加一个空参构造
添加一个带异常信息的构造
}
注意:
1、自定义异常类一般以Exception结尾,说明该类是异常类
2、必须继承Exception或RuntimeException
public class RegisterExceptionDemo9 extends Exception{
//空参构造
public RegisterExceptionDemo9() {
super();
}
/**
* 添加一个带异常信息的构造方法
* 查看源码发现,所有异常类都有一个带异常信息的构造,方法内部会调用父类带异常信息的构造,让父类处理
*
*/
public RegisterExceptionDemo9(String message){
super(message);
}
}