Java中如何返回回调void重写方法内获取的返回值?
问题描述
现有一个需要返回long类型值的函数,需要返回的目标值result.id.longValue()只能在回调的重写void方法内获取,无法直接在重写方法中把值return给外层函数,原错误实现代码如下:
public long functionName() { try { valueSystem .setResultCallback( new CustomCallback<CustomObject>() { @Override public void onCompletion(CustomObject result) { // 这里return无效:onCompletion本身是void返回值,也没法把值传给外层functionName return result.id.longValue(); } }); } catch (Exception e) { System.out.println(e.toString()); } }
用到的回调接口定义如下:
public interface MailboxCallback<T> { public void onCompletion(T result); }
注意:你贴的代码里回调接口名前后不一致(注册回调时写的是
CustomCallback,接口定义写的是MailboxCallback),实际开发时和项目中实际的类名保持一致即可。
问题根因
这是异步回调场景的典型问题:
- 从语法层面看,
onCompletion方法本身定义为void返回值,本身就不支持返回long类型值; - 从执行逻辑看,
setResultCallback只是注册回调,不会同步等待回调执行完成。外层functionName()方法执行结束时,onCompletion大概率还没被触发,就算你能在回调里写return,值也传不到外层的调用方。
可行实现方案
根据你的业务场景(是否允许阻塞调用线程),可以选以下三种方案:
方案1:CountDownLatch同步阻塞(最小改动适配原有逻辑)
如果你的场景允许外层调用线程阻塞等待结果,可以用CountDownLatch做线程间同步,用变量容器暂存回调拿到的结果,等回调执行完成后再把结果返回。
import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public long functionName() { // 用长度为1的数组暂存结果,绕开匿名内部类只能访问final变量的限制,也可以用AtomicLong替代 final long[] resultHolder = new long[1]; final CountDownLatch latch = new CountDownLatch(1); try { valueSystem.setResultCallback(new CustomCallback<CustomObject>() { @Override public void onCompletion(CustomObject result) { resultHolder[0] = result.id.longValue(); latch.countDown(); // 拿到结果后释放等待 } }); // 阻塞等待回调执行,最多等待5秒,超时时间根据业务实际情况调整,不要设置无限等待 boolean callbackExecuted = latch.await(5, TimeUnit.SECONDS); if (!callbackExecuted) { throw new RuntimeException("获取结果超时"); } } catch (Exception e) { System.out.println(e.toString()); // 异常/超时场景可以返回业务约定的默认值,或者直接抛出异常 return -1L; } return resultHolder[0]; }
- 适用场景:非UI线程、非事件循环线程的后端逻辑,不想改动原有方法的返回值签名。
- 注意点:必须设置合理的超时时间,避免回调永远不触发导致线程永久卡死。
方案2:改造为异步回调风格(符合异步API设计规范)
不要强行把异步逻辑转成同步返回,直接调整方法签名,让调用方传入结果处理回调,等拿到值后直接触发调用方的逻辑即可,全程不会阻塞线程。
// 方法不再直接返回long,而是接收上层传入的结果回调 public void functionName(ResultCallback callback) { try { valueSystem.setResultCallback(new CustomCallback<CustomObject>() { @Override public void onCompletion(CustomObject result) { long id = result.id.longValue(); callback.onSuccess(id); } }); } catch (Exception e) { System.out.println(e.toString()); callback.onError(e); } } // 上层用的结果回调接口,按需定义即可 public interface ResultCallback { void onSuccess(long id); void onError(Exception e); }
- 适用场景:UI线程、高并发服务等不允许阻塞线程的场景,是异步编程的标准实现方式。
- 调用示例:
functionName(new ResultCallback() { @Override public void onSuccess(long id) { // 在这里写拿到id之后的业务逻辑 } @Override public void onError(Exception e) { // 处理异常 } });
方案3:CompletableFuture包装(Java 8+推荐,兼顾同步/异步需求)
用JDK自带的CompletableFuture包装异步结果,灵活性最高:既可以同步阻塞拿结果,也可以链式添加异步处理逻辑,不用自己定义额外的回调接口。
import java.util.concurrent.CompletableFuture; public CompletableFuture<Long> functionName() { CompletableFuture<Long> resultFuture = new CompletableFuture<>(); try { valueSystem.setResultCallback(new CustomCallback<CustomObject>() { @Override public void onCompletion(CustomObject result) { resultFuture.complete(result.id.longValue()); } }); } catch (Exception e) { resultFuture.completeExceptionally(e); } return resultFuture; }
- 同步拿值示例:
try { Long id = functionName().get(5, TimeUnit.SECONDS); } catch (Exception e) { // 处理超时、异常 } - 异步处理示例:
functionName() .thenAccept(id -> { // 异步拿到id后执行的逻辑,不会阻塞线程 }) .exceptionally(e -> { // 处理异常 return null; });
内容的提问来源于stack exchange,提问作者Adam Lee
相关产品推荐
相关产品推荐

