Java › Functional Interfaces & Method References
How would you design a fluent, chainable validation API using functional interfaces, similar to how Comparator's thenComparing() works, but for validation rules that accumulate error messages rather than short-circuiting on the first failure?
AdvancedAnswer
Unlike Predicate's and()/or() (which short-circuit and only report pass/fail), a validation-accumulating design typically defines a custom functional interface returning a richer result type (like a List<String> of error messages, or a ValidationResult record) rather than a plain boolean, with a custom 'combine' default method that runs both validators regardless of the first one's outcome and merges their respective error lists together -- this lets you collect ALL validation failures for comprehensive error reporting (valuable for user-facing form validation, where showing every problem at once is more helpful than only the first one encountered) rather than Predicate's short-circuiting all-or-nothing boolean result.
@FunctionalInterface
interface Validator<T> {
List<String> validate(T input);
default Validator<T> and(Validator<T> other) {
return input -> {
List<String> errors = new ArrayList<>(this.validate(input));
errors.addAll(other.validate(input)); // accumulates BOTH, doesn't short-circuit
return errors;
};
}
}
Validator<String> notEmpty = s -> s.isEmpty() ? List.of("must not be empty") : List.of();
Validator<String> maxLength = s -> s.length() > 20 ? List.of("too long") : List.of();
Validator<String> combined = notEmpty.and(maxLength);
System.out.println(combined.validate("")); // reports BOTH applicable errors if both rules failReal-world example A registration form's custom Validator-based composition reports every validation rule that failed for a given field simultaneously (empty AND too long, if both apply), giving the user complete feedback in one pass, a meaningfully better user experience than Predicate's short-circuiting and()/or() would provide for this specific accumulating use case.