使用Java Optional重写注册逻辑时如何抛出不同的自定义异常
Optional场景下抛出不同业务异常的实现方案
你可以直接在映射后的User处理逻辑中,调用Optional.ifPresent()在检测到存在对应记录时直接抛出指定异常,不需要等到最后统一用orElseThrow处理,两种实现方式如下:
全链式调用写法
public User signup(UserDTO userDTO) throws Exception { return Optional.of(userDTO) .map(u -> modelMapper.map(u, User.class)) .map(user -> { // 邮箱重复校验 userRepo.findByEmail(user.getEmail()) .ifPresent(exist -> { throw new EmailAlreadyUsedException(); }); // 用户名重复校验 userRepo.findByUsername(user.getUsername()) .ifPresent(exist -> { throw new UsernameAlreadyUsedException(); }); // 赋值属性 user.setId(UUID.randomUUID().toString()); // 其他属性赋值,比如密码加密逻辑 return user; }) .map(userRepo::save) .orElseThrow(() -> new IllegalArgumentException("非法的用户注册参数")); }
可读性优化的拆分写法
不需要为了用Optional强制所有逻辑走链式调用,拆分后的写法更易维护:
public User signup(UserDTO userDTO) throws Exception { User user = Optional.of(userDTO) .map(u -> modelMapper.map(u, User.class)) .orElseThrow(() -> new IllegalArgumentException("非法的用户注册参数")); // 单独做业务校验 userRepo.findByEmail(user.getEmail()).ifPresent(exist -> {throw new EmailAlreadyUsedException();}); userRepo.findByUsername(user.getUsername()).ifPresent(exist -> {throw new UsernameAlreadyUsedException();}); user.setId(UUID.randomUUID().toString()); // 其他属性赋值 return userRepo.save(user); }
注意事项
- 如果你自定义的
EmailAlreadyUsedException、UsernameAlreadyUsedException是受检异常(继承Exception而非RuntimeException),需要在lambda中捕获后转为运行时异常抛出,或者调整自定义异常的继承结构为RuntimeException子类即可直接抛出。 - 末尾的
orElseThrow只有在入参userDTO为null时才会触发,你可以根据业务需要替换为更贴合的异常类型,不需要使用通用的Exception。
内容的提问来源于stack exchange,提问作者Davis
相关产品推荐
相关产品推荐

