Java中并行执行同接口不同泛型上下文校验器的方法
问题根因
Java泛型默认是不变型的,ValidatorInterface<ContextBase>和ValidatorInterface<ReturnContext>不存在继承关系。你当前实现的runValidators方法仅接受List<ValidatorInterface<T>>类型参数,当泛型T指定为ReturnContext时,列表只能存放绑定ReturnContext类型的校验器,绑定ContextBase的AlphaValidator无法加入列表,会直接触发编译期类型不匹配错误。
实现方案
遵循泛型PECS(Producer Extends, Consumer Super)原则调整代码即可:校验器的perform方法是消费context实例的(将context作为入参接收),因此将校验器列表的泛型声明改为? super T,就能兼容所有支持接收T类型或T的父类型的校验器,完全满足类型安全要求。
修改后的ValidatorRunner代码
public class ValidatorRunner<T extends ContextBase> { public List<String> runValidators(final T context, // 调整泛型通配符,兼容所有可消费T类型的校验器 final List<ValidatorInterface<? super T>> validatorsList) { final Map<String, CompletableFuture<List<String>>> futureAggregatedProblems = new LinkedHashMap<>(validatorsList.size()); List<String> problems = new ArrayList<>(); validatorsList.forEach(validator -> runValidator( validator, futureAggregatedProblems, context)); futureAggregatedProblems.forEach((validatorName, futureProblems) -> { try { problems.addAll(futureProblems.get(FUTURE_TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException | ExecutionException | CompletionException | TimeoutException ex) { // 正确处理中断:恢复线程中断标记后再抛出异常,避免吞掉中断状态 if (ex instanceof InterruptedException) { Thread.currentThread().interrupt(); } throw new InternalServiceException("Error executing validators : " + ex.getMessage(), ex); } }); return problems; } // 同步调整私有方法的泛型声明 private void runValidator(final ValidatorInterface<? super T> validator, final Map<String, CompletableFuture<List<String>>> futureAggregatedProblems, final T context) { // 此处类型完全安全:validator支持的入参类型是T或T的父类,传入T实例符合里氏替换原则 futureAggregatedProblems.put(validator.getClass().getCanonicalName(), validator.perform(context)); } }
调用示例
修改完成后,传入ReturnContext时可同时加入AlphaValidator和BetaValidator并行执行,代码可正常编译运行:
ValidatorRunner<ReturnContext> validatorRunner = new ValidatorRunner<>(); ReturnContext context = new ReturnContext(); AlphaValidator alpha = new AlphaValidator(); BetaValidator beta = new BetaValidator(); List<ValidatorInterface<? super ReturnContext>> validatorList = new ArrayList<>(); validatorList.add(alpha); validatorList.add(beta); List<String> problems = validatorRunner.runValidators(context, validatorList);
扩展场景适配
该实现完全兼容后续的业务扩展需求:
- 新增
ReplacementContext extends ContextBase和绑定该类型的GammaValidator时,只需创建ValidatorRunner<ReplacementContext>实例,在校验器列表中加入AlphaValidator和GammaValidator即可正常执行 - 由于
BetaValidator绑定ReturnContext、GammaValidator绑定ReplacementContext,二者类型无父子关系,无法被加入对方的校验器列表,天然满足不同业务上下文校验器不混合执行的要求
注意:原代码中标记的InterruptedException处理问题需要修复,捕获到中断异常时必须恢复线程的中断标记,不能直接吞掉中断状态,否则会破坏上层组件的线程中断控制逻辑。
内容的提问来源于stack exchange,提问作者Sarthak Shah
相关产品推荐
相关产品推荐

