开发一个用户注册验证系统,对用户输入的注册信息进行校验。当输入不合法时,使用 自定义异常 和 多 catch 处理 给出明确提示。
定义以下自定义异常类(继承 Exception —— 编译期异常):
// 用户名不能为空异常
class UsernameEmptyException extends Exception {
public UsernameEmptyException(String message) {
super(message);
}
}
// 用户名长度异常(长度必须在 3~12 个字符之间)
class UsernameLengthException extends Exception {
public UsernameLengthException(String message) {
super(message);
}
}
// 密码不能为空异常
class PasswordEmptyException extends Exception {
public PasswordEmptyException(String message) {
super(message);
}
}
// 密码强度异常(必须包含数字和字母,长度 >= 6)
class PasswordWeakException extends Exception {
public PasswordWeakException(String message) {
super(message);
}
}
// 年龄异常(年龄必须在 0~150 之间)
class AgeInvalidException extends Exception {
public AgeInvalidException(String message) {
super(message);
}
}
public class RegisterService {
/**
* 验证用户名
* @param username 用户名
* @throws UsernameEmptyException 用户名为空
* @throws UsernameLengthException 用户名长度不在 3~12 之间
*/
public static void validateUsername(String username)
throws UsernameEmptyException, UsernameLengthException {
// 1. 如果 username 为 null 或 trim() 后长度为 0,抛出 UsernameEmptyException
// 提示信息:"用户名不能为空!"
// 2. 如果 username.length() < 3 或 > 12,抛出 UsernameLengthException
// 提示信息:"用户名长度必须在 3~12 个字符之间!"
// 请补充代码
}
/**
* 验证密码
* @param password 密码
* @throws PasswordEmptyException 密码为空
* @throws PasswordWeakException 密码强度不足
*/
public static void validatePassword(String password)
throws PasswordEmptyException, PasswordWeakException {
// 1. 如果 password 为 null 或 trim() 后长度为 0,抛出 PasswordEmptyException
// 提示信息:"密码不能为空!"
// 2. 如果 password.length() < 6,抛出 PasswordWeakException
// 提示信息:"密码长度不能少于 6 位!"
// 3. 如果 password 不包含数字或字母(判断技巧:使用正则或循环遍历逐个字符检查),
// 抛出 PasswordWeakException
// 提示信息:"密码必须包含数字和字母!"
// 请补充代码(建议:使用循环遍历 + 两个 boolean 标记)
}
/**
* 验证年龄
* @param age 年龄字符串
* @throws NumberFormatException 年龄不是数字
* @throws AgeInvalidException 年龄超出范围
*/
public static void validateAge(String age)
throws NumberFormatException, AgeInvalidException {
// 1. 使用 Integer.parseInt(age) 转换为 int
// 如果 age 不是有效数字,NumberFormatException 会自动抛出(无需手动处理)
// 2. 如果 age < 0 或 age > 150,抛出 AgeInvalidException
// 提示信息:"年龄必须在 0~150 之间!"
// 请补充代码
}
/**
* 注册用户
* @param username 用户名
* @param password 密码
* @param age 年龄
*/
public static void register(String username, String password, String age) {
// 要求:
// 1. 使用 try-catch-finally 调用各验证方法
// 2. 按顺序验证:用户名 → 密码 → 年龄
// 3. 每个验证都有独立的 catch 块,输出对应的错误提示
// 4. 如果所有验证都通过,输出:"注册成功!欢迎 " + username
// 5. 注意:validateAge() 可能抛出 NumberFormatException,也需要捕获
// 6. 【新增】添加 finally 块,无论注册成功还是失败,都输出:
// "—— 注册操作日志:用户名=" + username + ",结果=" + (是否成功 ? "成功" : "失败")
// 提示:可以在 try 块成功时用一个 boolean 变量标记成功,finally 中读取该变量
// 请补充代码
}
public static void main(String[] args) {
// 测试用例
System.out.println("========== 测试 1:正常注册 ==========");
register("张三丰", "abc123", "25");
System.out.println("\n========== 测试 2:用户名为空 ==========");
register("", "abc123", "25");
System.out.println("\n========== 测试 3:用户名太短 ==========");
register("12", "abc123", "25");
System.out.println("\n========== 测试 4:密码太短 ==========");
register("张三丰", "12", "25");
System.out.println("\n========== 测试 5:密码不包含数字 ==========");
register("张三丰", "abcdef", "25");
System.out.println("\n========== 测试 6:年龄不是数字 ==========");
register("张三丰", "abc123", "二十五");
System.out.println("\n========== 测试 7:年龄超出范围 ==========");
register("张三丰", "abc123", "200");
System.out.println("\n========== 测试 8:综合错误(多错误按顺序只报第一个)==========");
register("", "", "abc"); // 应该只报用户名错误,不会检查密码和年龄
}
}
========== 测试 1:正常注册 ==========
注册成功!欢迎 张三丰
—— 注册操作日志:用户名=张三丰,结果=成功
========== 测试 2:用户名为空 ==========
用户名不能为空!
—— 注册操作日志:用户名=,结果=失败
========== 测试 3:用户名太短 ==========
用户名长度必须在 3~12 个字符之间!
—— 注册操作日志:用户名=12,结果=失败
========== 测试 4:密码太短 ==========
密码长度不能少于 6 位!
—— 注册操作日志:用户名=张三丰,结果=失败
========== 测试 5:密码不包含数字 ==========
密码必须包含数字和字母!
—— 注册操作日志:用户名=张三丰,结果=失败
========== 测试 6:年龄不是数字 ==========
年龄格式错误:二十五 不是有效的数字!
—— 注册操作日志:用户名=张三丰,结果=失败
========== 测试 7:年龄超出范围 ==========
年龄必须在 0~150 之间!
—— 注册操作日志:用户名=张三丰,结果=失败
========== 测试 8:综合错误 ==========
用户名不能为空!
—— 注册操作日志:用户名=,结果=失败
Exception(编译期异常),这有什么影响?如果改为继承 RuntimeException,代码会有什么变化?register() 方法中,每个验证方法都有自己的 catch 块,而不是用一个大 catch (Exception e) 统一处理?这样做的好处是什么?register() 方法使用 finally 输出了操作日志。如果不用 finally,把日志输出放在 try 块末尾和每个 catch 块中分别写一次,是否能达到同样效果?这样做有什么弊端?(提示:代码重复、遗漏风险)return 语句,finally 块还会执行吗?请编写一个小测试验证你的结论。