Java Future API中如何将Future返回的泛型值传递给特定参数类型的回调函数
看起来你现在遇到的核心问题是泛型回调和Future泛型类型不匹配——你的genericFutureHandler是泛型的,但CompletionAction接口的方法参数固定成了int,这就导致当Future的泛型类型不是int时,代码根本编译不过。其实只需要把回调接口也改成泛型的,就能完美实现你要的“透明处理任意Future值并传给回调”的需求,下面一步步来改:
第一步:把CompletionAction改成泛型接口
将原来固定参数的接口改成泛型,让它能适配任意类型的Future结果:
interface CompletionAction<T> { void showCompletedTask(T result); }
方法名我稍微改得更通用了些,你要是想保留原来的showCompletedTaskNumber也完全没问题,核心是把参数从固定int换成泛型T。
第二步:修改genericFutureHandler,绑定泛型回调和Future类型
调整方法的回调参数,让它和Future<T>的泛型类型一一对应,这样就能安全地把Future的结果传给回调:
private static <T> void genericFutureHandler(List<Future<T>> futures, CompletionAction<T> completionAction) throws InterruptedException { for (Future<T> f : futures) { if (f.isDone()) { try { T result = f.get(); // 现在泛型结果可以直接传递给回调,类型完全匹配 completionAction.showCompletedTask(result); } catch (ExecutionException e) { e.printStackTrace(); // 这里可以考虑给回调加一个异常处理方法,比如onFailure,根据你的需求调整 } } } }
第三步:实现针对特定类型的回调
比如你原来处理int类型的需求,现在可以实现CompletionAction<Integer>,Java会自动拆箱Integer到int,完全不影响原有逻辑:
class TaskStatusCompletionAction implements CompletionAction<Integer> { @Override public void showCompletedTask(Integer taskNumber) { System.out.println("Task number : " + taskNumber + " completed"); } }
如果以后需要处理其他类型的Future,比如Future<String>,只需要新增对应的回调实现即可:
class StringTaskCompletionAction implements CompletionAction<String> { @Override public void showCompletedTask(String taskResult) { System.out.println("Task result: " + taskResult); } }
第四步:调用示例
现在你可以针对不同类型的Future列表,传入对应的回调,完全类型安全:
// 处理返回Integer的Future列表 List<Future<Integer>> intFutures = new ArrayList<>(); // 往intFutures添加异步任务... genericFutureHandler(intFutures, new TaskStatusCompletionAction()); // 处理返回String的Future列表 List<Future<String>> stringFutures = new ArrayList<>(); // 往stringFutures添加异步任务... genericFutureHandler(stringFutures, new StringTaskCompletionAction());
另外补充一点:你原来的循环只检查一次f.isDone(),如果Future还没完成就直接跳过了。如果需要等待所有Future完成,可以把if (f.isDone())改成直接调用f.get()(会阻塞直到任务完成),或者用f.get(long timeout, TimeUnit unit)设置超时时间,根据你的业务需求调整即可。
备注:内容来源于stack exchange,提问作者Shades88

