这几天主要学习了Java当中的异常这一概念,直接看图
java.lang.Throwable类是java语言中所有错误或异常的超类(父类),其主要可以分为两类:
Exception:编译期异常,继续编译java程序出现的问题(其中又分为了运行期异常(RuntimeException)以及非运行时异常(IOException)。
Error:错误,错误就相当于程序得了一个无法治愈的毛病,必须修改源代码,程序才能继续执行。
那接下来说一下怎样处理异常:
1.throws关键字:(交给别人处理)
解释:当方法内部抛出异常对象的时候,我们就必须处理这个异常对象
可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理(也就是中断处理)
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数列表)
throws AAAException,BBBExcetpion ...{
throw new AAAException("产生原因");
throw new BBBException("产生原因");
...
}
下面有几个注意事项:
2.try…catch方法
格式:
try{
//可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
//异常的处理逻辑,异常异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}
...
catch(异常类名 变量名){
}
注意:
这里就要说到finally关键字
try{
//可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
//异常的处理逻辑,异常异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}
...
catch(异常类名 变量名){
}finally{
//无论是否出现异常都会执行
}
注意:
多个异常使用捕获的处理方式:
try {
int arr[] = {1,2,3};
System.out.println(arr[3]); //ArrayIndexOutOfBoundsException 越界异常
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e);
}
try {
List list = List.of(1, 2, 3);
System.out.println(list.get(3)); //ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e);
}
System.out.println("后续代码");
}
这里我们可以看到,list集合和arr[]数组都出现了(索引值)越界异常,我们这里多个异常分别使用try…catch语句分别处理,是否感觉有些繁琐?
try {
int[] arr = {1,2,3};
System.out.println(arr[3]); //exception ArrayIndexOutOfBoundsException 越界异常
List list = List.of(1, 2, 3);
System.out.println(list.get(3)); //exception ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e);
} catch (IndexOutOfBoundsException e) {
System.out.println(e);
}
这里我们可以看到,try语句里我们将两个越界异常同时捕获了,但是使用两个catch语句来多次处理,值得注意的是 ArrayIndexOutOfBoundsException 是
IndexOutOfBoundsException 的子类,根据刚才注意事项,我们知晓应该将子类写在上面。
try {
int[] arr = {1,2,3};
System.out.println(arr[3]); //exception ArrayIndexOutOfBoundsException 越界异常
List list = List.of(1, 2, 3);
System.out.println(list.get(3)); //exception ArrayIndexOutOfBoundsException
} catch (Exception e) {
System.out.println(e);
}
System.out.println("后续代码");
那么这边多个异常的多种处理方式也整理完了。最后提醒一点,例如运行时异常被抛出可以不处理。即不捕获也不声明抛出,默认给虚拟机处理,终止程序,什么时候不抛出运行时异常了,再来继续执行程序。
答:主要是根据自己的需求,出现异常的时候,做特殊的处理。所以尽管Java已经预定义了许多异常类,但有时还需要定义自己的异常。
那么接下来是自定义类的格式:
自定义异常类:
java提供的异常类,不够我们使用,需要自己定义一些异常类
格式:
public class XXXException extends Exception / RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
注意:
这里我们拟做一个登记注册的流程,输出自己注册的ID,如果数据库里又相同的已经注册过的ID,那么就会报错,没有则提示注册成功。
这边先来看一下我们的RegisterException代码:
//继承运行期异常
public class RegisterException extends RuntimeException{
//添加一个空参数的构造方法
public RegisterException() {
}
//添加一个异常信息的构造方法
//查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类处理这个异常信息。
public RegisterException(String message) {
super();
}
}
接下里我们来看主方法,并定义一个方法,用来对用户输入的注册用户名进行判断。
public class Demo01RegisterException {
//1.使用数组保存已经注册过的用户名
static String[] userNames = {"张三","李四","王五"};
public static void main(String[] args) throws RegisterException {
//2.使用Scanner获取用户输入的注册的用户名(前端,页面)
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要注册的用户名:");
String username = sc.next();
checkUsername(username);
}
//3.定义一个方法,对用户输入的注册的用户名进行判断
public static void checkUsername(String username) /*throws RegisterException*/ {
//遍历存储已经注册过用户名的数组,获取每一个用户名
for(String name : userNames) {
//使用获取到的用户名和用户输入的用户名比较
if(name.equals(username)) {
//true:用户名已经存在了,抛出RegisterException异常,告知用户“亲,该用户名已经被注册”;
try {
throw new RegisterException("亲,该用户名已经被注册");
} catch (RegisterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return; //结束方法
}
}
}
System.out.println("恭喜您,注册成功!");
}
}
这里使用try…catch语句。那么我们知道,由于我们的自定义异常类继承的是RuntimeException,也就是运行期异常,由上面可知运行期异常,我们也可以不处理,直接交给虚拟机处理。
public class Demo02RegisterException {
//1.使用数组保存已经注册过的用户名
static String[] userNames = {"张三","李四","王五"};
public static void main(String[] args) throws RegisterException {
//2.使用Scanner获取用户输入的注册的用户名(前端,页面)
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要注册的用户名:");
String username = sc.next();
checkUsername(username);
}
//3.定义一个方法,对用户输入的注册的用户名进行判断
public static void checkUsername(String username) /*throws RegisterException*/ {
//遍历存储已经注册过用户名的数组,获取每一个用户名
for(String name : userNames) {
//使用获取到的用户名和用户输入的用户名比较
if(name.equals(username)) {
//true:用户名已经存在了,抛出RegisterException异常,告知用户“亲,该用户名已经被注册”;
throw new RegisterException("亲,该用户名已经被注册"); //抛出运行期异常,无需处理,交给JVM处理,中断处理
}
}
System.out.println("恭喜您,注册成功!");
}
}
如上面的代码所示,我们这里既没有throw抛出异常,也没有try…catch处理。但是代码也不会报错。