【Java异常处理】6-3 自定义异常
§6-3 自定义异常
本节内容将介绍如何自定义异常。
使用 Java 内置的异常类可以描述编程过程中出现的大部分异常情况。除此之外,用户还可以自定义异常。
6-3.1 自定义异常的步骤
在开发过程中,若 Java 所提供的异常无法满足需求时,开发者可自定义异常。
自定义异常,大体可分为以下几个步骤:
-
创建自定义异常类,类名应当见名知意;
异常类类名应当为
XXXException
,其中XXX
表示当前异常的名字,指出问题; -
根据异常的分类(运行时异常或编译时异常),编写继承关系;
若是运行时异常,继承
RuntimeException
;若是编译时异常,直接继承Exception
;编译时异常用于提醒程序员应当检查本地信息,而运行时异常是参数非法或程序运行逻辑有误所导致的问题;
-
提供无参与有参构造器,让控制台的报错信息更加见名知意;
示例:
现有一个 Java Bean 类:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
//姓名参数为空
if (name == null)
throw new NullPointerException();
//长度不满足条件
if (name.length() < 2 || name.length() > 10)
throw new IllegalNameException("\"" + name + "\" 参数不合法,应当为为一个 2 - 10 字符的字符串。");
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
if (age < 18 || age > 40)
throw new IllegalAgeException("\"" + age + "\"参数不合法,应当为范围 18-40 的整数。");
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
针对非法姓名和非法年龄参数,分别设计运行时异常类:
public class IllegalNameException extends RuntimeException {
public IllegalNameException() {
}
public IllegalNameException(String message) {
super(message);
}
}
public class IllegalAgeException extends RuntimeException {
public IllegalAgeException() {
}
public IllegalAgeException(String message) {
super(message);
}
}
在测试类中,让用户输入上述学生类的信息,若参数非法,则应当重复提示输入,直到得到期望结果为止。
import java.util.Scanner;
public class CustomTest {
public static void main(String[] args) {
//姓名 2 - 10个字符
//年龄 18 - 40
//输入错误应当循环,直至得到正确数据为止
Scanner scanner = new Scanner(System.in);
//创建学生对象
Student student = new Student();
String name = "";
while (true) {
try {
System.out.println("请输入姓名:");
name = scanner.nextLine();
student.setName(name);
break;
} catch (IllegalNameException e) {
System.err.println(e);
} catch (NullPointerException e) {
System.err.println("姓名参数为空(null)。");
}
}
int age = 0;
while (true) {
try {
System.out.println("请输入年龄:");
age = scanner.nextInt();
student.setAge(age);
break;
} catch (IllegalAgeException e) {
System.err.println(e);
}
}
System.out.println(student);
scanner.close();
}
}
使用 err
标准错误流打印信息,控制台中显示的字体将为红色,更加醒目。
上述程序还可以做进一步的优化。
优化方案一:使用 nextInt()
方法接收整型,很有可能会因为用户的意外输入而抛出 InputMisMatch
异常。因此,一般而言,先以字符串形式接收,再使用包装类解析。解析过程中可能会由于数据格式错误而抛出 NumberFormatException
,可用同样的方法重复提醒用户重新输入,知道得到期望的数据为止。
优化方案二:考虑全部先使用字符串接收数据,使用正则表达式过滤非法数据,抛出异常。此时可根据过滤的内容,再自定义更为特定的异常。
6-3.2 在实践中的经验总结
- 处理运行时异常时,采用逻辑去合理规避异常,同时用
try-catch
辅助处理; - 在多重
catch
块后面,可以添加catch(Exception e)
捕获处理可能遗漏的异常; - 对于不确定的代码,也可以加上
try-catch
,处理潜在的异常; - 尽量去处理异常,切忌简单地输出打印异常;
- 处理异常的具体方法,应当由不同的业务需求和业务类型决定;
- 尽量添加
finally
语句块释放占用资源。