【Java异常处理】6-3 自定义异常

§6-3 自定义异常

本节内容将介绍如何自定义异常。

使用 Java 内置的异常类可以描述编程过程中出现的大部分异常情况。除此之外,用户还可以自定义异常。

6-3.1 自定义异常的步骤

在开发过程中,若 Java 所提供的异常无法满足需求时,开发者可自定义异常。

自定义异常,大体可分为以下几个步骤:

  1. 创建自定义异常类,类名应当见名知意;

    异常类类名应当为 XXXException,其中 XXX 表示当前异常的名字,指出问题;

  2. 根据异常的分类(运行时异常或编译时异常),编写继承关系;

    若是运行时异常,继承 RuntimeException;若是编译时异常,直接继承 Exception

    编译时异常用于提醒程序员应当检查本地信息,而运行时异常是参数非法或程序运行逻辑有误所导致的问题;

  3. 提供无参与有参构造器,让控制台的报错信息更加见名知意;

示例

现有一个 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 语句块释放占用资源。
posted @ 2023-07-15 18:50  Zebt  阅读(179)  评论(0)    收藏  举报