Java中的自定义异常

引言

Java编程中,异常处理是很关键的一步操作,它可以帮助我们更好的管理程序中的错误问题,Java本身内置了许多异常,但项目中我们需要自定义异常来提升错误问题的可读性和用户的产品体验,本文将深入探讨Java中的自定义异常,包括其原理、用法和最佳实践

异常是什么,如何处理?

异常是在程序执行过程中发送的不正常情况,它会中断程序的正常流程,Java 使用异常类来表示不同类型的异常情况,这些异常类就继承了异常超类 Throwable

异常分为两个类型:受检异常和非受检异常

受检异常:编译时必须被处理的异常,否则程序无法编译通过非受检异常:运行时可能发生的异常

Java中处理异常使用 try-catch 语句块来捕获并处理,在 try 块中包含可能会排除异常的代码,而在 catch 块中则处理相应的异常,如果在 try 块中发生了异常,程序就会立即跳转到相应的 catch 块中进行处理,如果没有匹配的 catch 块,异常会向上抛出,知道被最高层次的异常处理机制捕获或者导致程序终止

自定义异常

模仿 Java 自带的异常类进行自定义异常类的编写

继承异常类:如果是自定义受检异常就继承 Exception 类或其子类,如果是自定义非受检异常就继承 RuntimeException编写构造方法:合适的构造方法有助于异常信息和对象的传递,通常传递一个字符串用于给用户友好提示即可抛出异常:在程序中,使用 throw 语句来抛出自定义异常对象捕获和处理异常:使用 try-catch 语句块来捕获和处理自定义异常,catch块中进行异常处理

代码示例

通常我们自定义异常就是非受检异常,即运行时发生的异常,以下是自定义非受检异常为例所编写的代码实例

承接我的上篇文章,Java中实现RSA非对称加密算法对数据进行加密解密,我们在项目的登录接口中抛出自定义异常编写简单的代码示例

创建存放自定义异常的包

创建自定义异常类

/**

* 自定异常

* @author muze

*/

public class CustomException extends RuntimeException {

@Serial

private static final long serialVersionUID = -1;

/**

* 构造函数

* @param message 给用户提示的友好信息

*/

public CustomException(String message) {

super(message);

}

}

修改登录接口实现

/**

* 用户业务实现层

* @author muze

*/

@Service

public class UserServiceImpl implements IUserService {

/**

* 注入用户数据层

*/

@Autowired

private UserMapper userMapper;

@Override

public String login(UserLoginDTO userLoginDTO) {

// 取出用户名和密码

String username = userLoginDTO.getUsername();

String password = userLoginDTO.getPassword();

// 构建查询条件

LambdaQueryWrapper userLambdaQueryWrapper = new LambdaQueryWrapper().eq(User::getUsername, username);

// 查询用户

User user = userMapper.selectOne(userLambdaQueryWrapper);

//************************ 新增密码解密 ************************//

String decryptPassword;

try {

decryptPassword = RSAUtil.decryptByPrivateKey(password);

} catch (Exception e) {

//************************ 抛出自定义异常 ************************//

throw new CustomException("用户名或密码错误");

}

// 如果用户为空或者解密后的输入密码与用户密码不匹配则返回:用户名或密码错误

if (user == null || !decryptPassword.equals(user.getPassword())) return "用户名或密码错误";

// 使用SaToken的工具类StpUtil调用登录方法login,入参:用户id

StpUtil.login(user.getId());

// 返回:登录成功

return "登录成功";

}

}

修改用户控制层

捕获自定义异常并处理

/**

* 用户控制层

* @author muze

*/

//************************ 新增日志打印 ************************//

@Slf4j

@RestController

@RequestMapping("/user")

public class UserController {

/**

* 注入用户业务接口层

*/

@Autowired

private IUserService userService;

/**

* 登录

* @param userLoginDTO 用户登录请求实体

* @return 响应码 + 响应消息 + 响应数据

*/

@PostMapping("/login")

public SaResult login(@RequestBody UserLoginDTO userLoginDTO) {

//************************ 新增捕获自定义异常并处理 ************************//

try {

return SaResult.ok(userService.login(userLoginDTO));

} catch (CustomException e) {

// 打印自定义异常信息

log.error("自定义异常:", e);

return SaResult.error(e.getMessage());

}

}

}

测试

运行程序,输入未用公钥加密密码进行登录,程序会在密码解密时抛出自定义异常,控制台和接口调用工具可以看到如下结果

到这里我们就一起完成了Java中的自定义异常了,相信你已经掌握了,赶快去试试吧,希望这篇文章能对你有所帮助!

彩蛋:细心的你肯定发现了,在实际开发中是见不到控制层去捕获自定义异常并处理的,因为这样会有大量繁琐的重复工作,并且难以维护,不利于我们开发,时间成本也很高,所以我们需要通过AOP面向切面编程的方式去实现全局异常捕获和处理,从而减少繁琐大量重复工作,降低程序的维护难度,节省我们的开发时间,小编会在后续更新一篇与AOP面向切面编程实现全局异常捕获和处理的相关文章,敬请期待!

《旅行青蛙》幸运物、道具与食物的作用,青蛙去哪儿? 12月31日更新
随着克罗地亚3-0零封,荷兰4-0横扫,丹麦3-1碾压希腊,世欧预最新积分榜公开