背景
在 Java 开发中,重复代码常常让项目难以维护,增加了负担。Java 8 引入了函数式编程,尤其是 Function 接口,它提供了高效处理重复逻辑的工具。
本文展示了如何用 Java 8 的函数式特性来简化数据有效性校验,(可把有共性的检查抽离出来),减少代码重复。
场景示例:数据校验的困境
在复杂的业务系统中,常需要检查数据库字段值的有效性。
例如,验证用户 ID 和部门 ID 的存在性,传统做法需要手动编写大量查询代码,不仅冗长且维护困难:
public void checkUserExistence(String userId) {
User user = userDao.findById(userId);
if (user == null) {
throw new RuntimeException("用户ID无效");
}
}
public void checkDeptExistence(String deptId) {
Dept dept = deptDao.findById(deptId);
if (dept == null) {
throw new RuntimeException("部门ID无效");
}
}
使用函数式接口优化代码
Java 8 引入了 Function<T, R> 接口,允许将属性提取和查询逻辑封装成 Lambda 表达式,减少重复代码。SFunction 是一个对 Lambda 表达式的封装,使操作更简洁。
通用方法示例
以下方法 ensureColumnValueValid 实现了针对任意字段的通用校验:
public static <T, R, V> void ensureColumnValueValid(
V valueToCheck, SFunction<T, R> columnExtractor,
SFunction<LambdaQueryWrapper<T>, T> queryExecutor,
String errorMessage) {
if (valueToCheck == null) return;
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
wrapper.select(columnExtractor);
wrapper.eq(columnExtractor, valueToCheck);
wrapper.last("LIMIT 1");
T entity = queryExecutor.apply(wrapper);
if (entity == null || columnExtractor.apply(entity) == null) {
throw new DataValidationException(String.format(errorMessage, valueToCheck));
}
}
应用示例
public void assignTaskToUser(AddOrderDTO dto) {
ensureColumnValueValid(dto.getUserId(), User::getId, userDao::getOne, "用户ID无效");
ensureColumnValueValid(dto.getDeptId(), Dept::getId, deptDao::getOne, "部门ID无效");
}
这种方式减少了代码量,提高了代码的可读性和维护性。
拓展:高级校验逻辑
校验列值是否符合预期
validateColumnValueMatchesExpected 方法验证列值是否与预期值匹配:
public static <T, R, C> void validateColumnValueMatchesExpected(
SFunction<T, R> targetColumn, R expectedValue,
SFunction<T, C> conditionColumn, C conditionValue,
SFunction<LambdaQueryWrapper<T>, T> queryMethod,
String errorMessage) {
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
wrapper.select(targetColumn).eq(conditionColumn, conditionValue);
T one = queryMethod.apply(wrapper);
if (one != null && !Objects.equals(targetColumn.apply(one), expectedValue)) {
throw new RuntimeException(String.format(errorMessage, expectedValue));
}
}
校验值是否在预期值列表内
validateColumnValueInExpectedList 方法用于检查列值是否在一组期望值中:
public static <T, R, C> void validateColumnValueInExpectedList(
SFunction<T, R> targetColumn, List<R> expectedValueList,
SFunction<T, C> conditionColumn, C conditionValue,
SFunction<LambdaQueryWrapper<T>, T> queryMethod,
String errorMessage) {
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
wrapper.select(targetColumn).eq(conditionColumn, conditionValue);
T one = queryMethod.apply(wrapper);
if (one != null && !expectedValueList.contains(targetColumn.apply(one))) {
throw new RuntimeException(errorMessage);
}
}
优势总结
- 减少重复代码:复用
ensureColumnValueValid等方法,避免大量重复校验逻辑。 - 增强代码复用:通用校验方法适用于各种场景,能对不同实体的属性校验一体化处理。
- 提高可读性和维护性:函数式编程使代码结构清晰,减少了后续维护难度。
- 灵活性和扩展性:修改校验规则只需调整核心方法,所有调用处自动适配新规则。
总结
Java 8 的函数式编程极大地简化了代码逻辑,通过 Function 接口和 Lambda 表达式的组合,我们可以创建更简洁、灵活、易维护的代码。函数式编程思想值得在日常开发中深入探索,提升代码的优雅性和效率。