Refactoring Data Validation with Java 8 Functional Interfaces
This article demonstrates how Java 8's functional interfaces and lambda expressions can be used to abstract and reuse data validation logic, reducing repetitive code and improving readability and maintainability in backend services.
In Java development, repetitive validation code often leads to bulky projects and high maintenance costs. Java 8 introduces functional interfaces such as Function and MyBatis‑Plus's SFunction , which enable developers to encapsulate validation logic into reusable methods.
The article first shows typical validation methods that manually query the database and throw exceptions when a user ID or department ID is invalid:
// 判断用户 ID 是否有效
public void checkUserExistence(String userId) {
User user = userDao.findById(userId);
if (user == null) {
throw new RuntimeException("用户ID无效");
}
}
// 判断部门 ID 是否有效
public void checkDeptExistence(String deptId) {
Dept dept = deptDao.findById(deptId);
if (dept == null) {
throw new RuntimeException("部门ID无效");
}
}To eliminate duplication, a generic method ensureColumnValueValid is introduced. It receives the value to check, a column extractor, a query executor, and an error message template, performing the validation in a single place:
public static
void ensureColumnValueValid(V valueToCheck,
SFunction
columnExtractor,
SFunction
, T> queryExecutor,
String errorMessage) {
if (valueToCheck == null) return;
LambdaQueryWrapper
wrapper = new LambdaQueryWrapper<>();
wrapper.select(columnExtractor);
wrapper.eq(columnExtractor, valueToCheck);
wrapper.last("LIMIT 1");
T entity = queryExecutor.apply(wrapper);
R columnValue = columnExtractor.apply(entity);
if (entity == null || columnValue == null)
throw new DataValidationException(String.format(errorMessage, valueToCheck));
}Using this method, the original validation code can be refactored into concise calls:
public void assignTaskToUser(AddOrderDTO dto) {
ensureColumnValueValid(dto.getUserId(), User::getId, userDao::getOne, "用户ID无效");
ensureColumnValueValid(dto.getDeptId(), Dept::getId, deptDao::getOne, "部门ID无效");
ensureColumnValueValid(dto.getCustomerId(), Customer::getId, customerDao::getOne, "客户ID无效");
// further business logic ...
}The article then extends the idea with two more generic validators. validateColumnValueMatchesExpected checks whether a column value equals an expected value, while validateColumnValueInExpectedList verifies that a column value belongs to a predefined list. Both accept lambda expressions for the target column, condition column, and query execution, keeping the validation logic flexible and reusable.
public static
void validateColumnValueMatchesExpected(
SFunction
targetColumn, R expectedValue,
SFunction
conditionColumn, C conditionValue,
SFunction
, T> queryMethod,
String errorMessage) {
LambdaQueryWrapper
wrapper = new LambdaQueryWrapper<>();
wrapper.select(targetColumn);
wrapper.eq(conditionColumn, conditionValue);
T one = queryMethod.apply(wrapper);
if (one == null) return;
R actualValue = targetColumn.apply(one);
boolean doesNotMatch = notMatch(actualValue, expectedValue);
if (doesNotMatch) {
throw new RuntimeException(String.format(errorMessage, expectedValue, actualValue));
}
}
private static
boolean notMatch(R actual, R expected) {
return !Objects.equals(actual, expected);
} public static
void validateColumnValueInExpectedList(
SFunction
targetColumn, List
expectedValueList,
SFunction
conditionColumn, C conditionValue,
SFunction
, T> queryMethod,
String errorMessage) {
LambdaQueryWrapper
wrapper = new LambdaQueryWrapper<>();
wrapper.select(targetColumn);
wrapper.eq(conditionColumn, conditionValue);
T one = queryMethod.apply(wrapper);
if (one == null) return;
R actualValue = targetColumn.apply(one);
if (actualValue == null) throw new RuntimeException("列查询结果为空");
if (!expectedValueList.contains(actualValue)) {
throw new RuntimeException(errorMessage);
}
}These utilities dramatically reduce boilerplate, improve code clarity, and centralize exception handling. The article concludes that embracing Java 8 functional programming not only streamlines validation logic but also enhances testability and future extensibility across backend services.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.