当前位置: 首页 > news >正文

在日常开发中实现异常处理和空值处理的最佳实践

在日常开发中实现异常处理和空值处理的最佳实践

在日常开发中,良好的异常处理和空值处理是编写健壮、可维护代码的关键。以下是一些实用的最佳实践和具体实现方法:

1. 空值处理策略

1.1 使用 Optional 类

// 不推荐:直接返回可能为null的值
public String findUserName(Long userId) {User user = userRepository.findById(userId);return user != null ? user.getName() : null;
}// 推荐:使用Optional明确表示可能为空
public Optional<String> findUserName(Long userId) {return userRepository.findById(userId).map(User::getName);
}// 调用方处理
Optional<String> userName = findUserName(123L);
String name = userName.orElse("Unknown User");
// 或者
String name = userName.orElseThrow(() -> new UserNotFoundException("User not found: " + 123L));

1.2 使用 Objects 工具类

// 参数验证
public void processUser(User user) {Objects.requireNonNull(user, "User cannot be null");Objects.requireNonNull(user.getName(), "User name cannot be null");// 处理逻辑
}// 默认值处理
public String getUserDisplayName(User user) {String name = Objects.requireNonNullElse(user.getDisplayName(), "Anonymous");return name.trim();
}

1.3 集合空值处理

// 返回空集合而不是null
public List<String> getUserRoles(Long userId) {List<String> roles = userRoleRepository.findByUserId(userId);return roles != null ? roles : Collections.emptyList();
}// 使用Collections工具类
public List<String> getUserPermissions(Long userId) {return Optional.ofNullable(permissionRepository.findByUserId(userId)).orElse(Collections.emptyList());
}

1.4 字符串空值处理

// 使用StringUtils(Apache Commons Lang或Spring)
public String processInput(String input) {if (StringUtils.isEmpty(input)) {return "default";}return input.trim();
}// 或者使用Java 11+的isBlank
public String sanitizeInput(String input) {if (input == null || input.isBlank()) {return "";}return input.trim();
}

2. 异常处理策略

2.1 定义清晰的异常层次结构

// 基础业务异常
public abstract class BusinessException extends RuntimeException {private final String errorCode;public BusinessException(String errorCode, String message) {super(message);this.errorCode = errorCode;}public String getErrorCode() {return errorCode;}
}// 具体业务异常
public class UserNotFoundException extends BusinessException {public UserNotFoundException(Long userId) {super("USER_NOT_FOUND", "User not found with ID: " + userId);}
}public class InsufficientPermissionsException extends BusinessException {public InsufficientPermissionsException(String operation) {super("INSUFFICIENT_PERMISSIONS", "Insufficient permissions for operation: " + operation);}
}

2.2 使用全局异常处理器

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {// 处理业务异常@ExceptionHandler(BusinessException.class)public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {log.warn("Business exception: {}", ex.getMessage());ErrorResponse error = new ErrorResponse(ex.getErrorCode(),ex.getMessage(),HttpStatus.BAD_REQUEST.value());return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);}// 处理数据访问异常@ExceptionHandler(DataAccessException.class)public ResponseEntity<ErrorResponse> handleDataAccessException(DataAccessException ex) {log.error("Data access error", ex);ErrorResponse error = new ErrorResponse("DATA_ACCESS_ERROR","An error occurred while accessing data",HttpStatus.INTERNAL_SERVER_ERROR.value());return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);}// 处理参数验证异常@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField,fieldError -> fieldError.getDefaultMessage() != null ? fieldError.getDefaultMessage() : "Validation failed"));ErrorResponse error = new ErrorResponse("VALIDATION_FAILED","Input validation failed",HttpStatus.BAD_REQUEST.value(),errors);return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);}
}

2.3 异常处理工具类

@Slf4j
public final class ExceptionHandlingUtils {private ExceptionHandlingUtils() {// 工具类,防止实例化}// 安全执行操作,返回Optionalpublic static <T> Optional<T> executeSafely(Supplier<T> operation, String operationName) {try {return Optional.ofNullable(operation.get());} catch (Exception e) {log.warn("Operation {} failed: {}", operationName, e.getMessage());return Optional.empty();}}// 安全执行操作,提供默认值public static <T> T executeSafely(Supplier<T> operation, T defaultValue, String operationName) {try {T result = operation.get();return result != null ? result : defaultValue;} catch (Exception e) {log.warn("Operation {} failed: {}", operationName, e.getMessage());return defaultValue;}}// 安全执行操作,抛出特定异常public static <T, E extends RuntimeException> T executeOrThrow(Supplier<T> operation, Supplier<E> exceptionSupplier,String operationName) {try {T result = operation.get();if (result == null) {throw exceptionSupplier.get();}return result;} catch (Exception e) {log.error("Operation {} failed", operationName, e);throw exceptionSupplier.get();}}
}// 使用示例
public User findUserSafe(Long userId) {return ExceptionHandlingUtils.executeSafely(() -> userRepository.findById(userId),null,"findUserById");
}

2.4 资源管理和异常处理

// 使用try-with-resources确保资源释放
public String readFileContent(String filePath) {try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {StringBuilder content = new StringBuilder();String line;while ((line = reader.readLine()) != null) {content.append(line).append("\n");}return content.toString();} catch (IOException e) {throw new FileReadException("Failed to read file: " + filePath, e);}
}// 数据库事务中的异常处理
@Transactional
public void updateUserProfile(Long userId, UserProfile profile) {try {User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException(userId));user.setProfile(profile);userRepository.save(user);// 发送通知notificationService.sendProfileUpdateNotification(userId);} catch (NotificationException e) {// 记录日志但继续事务log.warn("Failed to send notification for user: {}", userId, e);// 事务不会回滚,因为NotificationException不是RuntimeException}
}

3. 日常开发中的实践建议

3.1 代码审查清单

在代码审查时,关注以下异常和空值处理方面:

  • 方法是否返回null而不是空集合?
  • 是否检查了参数的有效性?
  • 是否适当处理了可能为空的返回值?
  • 异常消息是否包含足够的上下文信息?
  • 是否捕获了过于宽泛的Exception?
  • 资源是否被正确关闭?
  • 日志记录是否适当?

3.2 单元测试中的异常测试

@Test
void shouldThrowExceptionWhenUserNotFound() {// 准备Long nonExistentUserId = 999L;// 执行和断言assertThrows(UserNotFoundException.class, () -> {userService.getUserDetails(nonExistentUserId);});
}@Test
void shouldReturnEmptyOptionalWhenUserNotFound() {// 准备Long nonExistentUserId = 999L;// 执行Optional<User> result = userService.findUser(nonExistentUserId);// 断言assertFalse(result.isPresent());
}@Test
void shouldHandleNullInputGracefully() {// 执行String result = stringProcessor.process(null);// 断言assertEquals("default", result);
}

3.3 使用断言进行防御性编程

public class ValidationUtils {public static void notNull(Object obj, String message) {if (obj == null) {throw new IllegalArgumentException(message);}}public static void notBlank(String str, String message) {if (str == null || str.trim().isEmpty()) {throw new IllegalArgumentException(message);}}public static void isTrue(boolean condition, String message) {if (!condition) {throw new IllegalArgumentException(message);}}
}// 在业务代码中使用
public void createUser(String username, String email) {ValidationUtils.notBlank(username, "Username cannot be blank");ValidationUtils.notBlank(email, "Email cannot be blank");ValidationUtils.isTrue(email.contains("@"), "Invalid email format");// 创建用户的逻辑
}

4. 总结

在日常开发中实现良好的异常和空值处理需要:

  1. 明确策略:确定何时使用Optional、何时抛出异常、何时返回默认值
  2. 一致性:在整个项目中保持一致的异常和空值处理模式
  3. 上下文信息:在异常和日志中包含足够的上下文信息以便调试
  4. 防御性编程:验证输入参数,使用断言防止无效状态
  5. 资源管理:确保资源正确释放,使用try-with-resources
  6. 测试覆盖:编写测试验证异常情况和边界条件

通过遵循这些最佳实践,您可以编写出更加健壮、可维护和可靠的代码。

http://www.dtcms.com/a/390420.html

相关文章:

  • openstack port binding failure (by quqi99)
  • leetcode 3484. 设计电子表格 中等
  • Docker+cpolar 实战:打造灵活可控的远程办公系统
  • uniApp开发XR-Frame微信小程序 | 设置透明贴图
  • M3 Ultra版Mac Studio无法正常升级到macOS 26.0 苹果已经在调查
  • 老的ios项目在新的mac M1上编译运行遇到的问题及整理
  • Java 大视界 -- Java 大数据机器学习模型在元宇宙虚拟场景智能交互中的关键技术
  • 2025年目标检测还有什么方向好发论文?
  • 离线openHarmonySdk鸿蒙系统动态库的封装
  • 从零实现鸿蒙智能设备数据采集:权限、传感器、云端上传全流程实战
  • 智慧医院IBMS中央集成系统解决方案:构建医疗安全优先的智慧运营中枢​
  • ✅ Python房源数据采集+分析+预测平台 requests爬虫+sklearn回归 大数据实战项目(建议收藏)机器学习(附源码)
  • 结婚证 OCR 识别:政务服务提速的 “关键一环”
  • Git企业开发--多人协作
  • 【论文阅读 | IF 2025 | IF-USOD:用于水下显著目标检测的多模态信息融合交互式特征增强架构】
  • 【14/20】安全强化:HTTPS 和率限制在 Express 中的应用,实现防护机制
  • C#调用钉钉API实现安全企业内部通知推送
  • MyBatis与MyBatis-Plus区别
  • 数据血缘探秘:用SQL串联不同数据源的脉络
  • 多线程程序性能优化:缓存命中率与伪共享深度剖析
  • Spring Boot支持哪些类型的自定义配置文件?
  • uniapp:scss变量使用方法
  • postman接口测试系列: 时间戳和加密
  • 模型蒸馏demo
  • 【JVM】Java中有哪些垃圾回收算法?
  • 为何楼宇自控系统日益受欢迎?解析其兴起的核心动因
  • ASP.NET Core RazorPages/MVC/Blazor/Razor/WebApi概念记录说明
  • .NET Core 中 RabbitMQ 和 MassTransit 的使用
  • 使用QT进行3D开发建模
  • 阿里云开源DeepResearch:轻量化AI推理框架技术解析与实践指南