You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Guava:仅在请求时转换ListenableFuture的实现方法

解决ListenableFuture串联时的延迟执行需求

首先得明确你遇到的核心问题:当原ListenableFuture已经完成时,调用Futures.transform会立刻执行传入的转换逻辑,哪怕你根本没去操作新生成的future。而你想要的是——只有当原future被主动触发(比如调用get()、添加Listener),或者新future被实际使用时,才执行doSomething。

下面给你两种靠谱的解决思路:

方案一:用Supplier延迟创建转换后的Future

利用Guava的Suppliers.memoize来包装转换逻辑,只有当你真正需要新future的时候,才会触发transform操作,进而执行doSomething。

import com.google.common.base.Suppliers;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.function.Function;

// 原future
ListenableFuture<Result> respFuture = ...;

// 用memoized Supplier包装转换逻辑,确保只创建一次
var lazyTransformedFuture = Suppliers.memoize(() -> 
    Futures.transform(respFuture, (Function<Result, Another>) result -> {
        // 这个doSomething只会在第一次获取lazyTransformedFuture.get()时才会执行(如果respFuture已完成)
        // 或者等respFuture完成后执行(如果respFuture还在运行)
        doSomething();
        return createAnotherResult(result);
    })
);

// 只有当你需要使用新future时,才调用get()
ListenableFuture<Another> anotherFuture = lazyTransformedFuture.get();

// 此时,只有当你调用anotherFuture.get()或者给它加Listener时,doSomething才会触发

这个方案的好处是简单,利用Guava现有API就能实现,不需要自己写包装类。

方案二:自定义懒加载的ListenableFuture

如果需要更灵活的控制,可以自己实现一个ForwardingListenableFuture,只有当新future被调用get()或者添加Listener时,才会关联原future的转换逻辑。

import com.google.common.util.concurrent.ForwardingListenableFuture;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.function.Function;

public class LazyTransformedFuture<Input, Output> extends ForwardingListenableFuture<Output> {
    private final ListenableFuture<Input> originalFuture;
    private final Function<Input, Output> transformFunction;
    private volatile ListenableFuture<Output> delegate;

    public LazyTransformedFuture(ListenableFuture<Input> originalFuture, Function<Input, Output> transformFunction) {
        this.originalFuture = originalFuture;
        this.transformFunction = transformFunction;
    }

    @Override
    protected ListenableFuture<Output> delegate() {
        // 双重检查锁,确保只初始化一次
        if (delegate == null) {
            synchronized (this) {
                if (delegate == null) {
                    delegate = Futures.transform(originalFuture, transformFunction);
                }
            }
        }
        return delegate;
    }
}

// 使用方式
ListenableFuture<Another> lazyAnotherFuture = new LazyTransformedFuture<>(respFuture, result -> {
    doSomething();
    return createAnotherResult(result);
});

// 只有当调用lazyAnotherFuture.get()或者addListener时,才会触发transform和doSomething

这个方案的优势是封装性更好,调用方不需要关心Supplier的存在,直接使用future即可。

最后再强调一下:如果原future还处于未完成状态,哪怕你直接调用Futures.transform,转换逻辑也不会立即执行——只有当原future完成时才会跑。你遇到的“立即执行”场景,大概率是原future已经完成了,这时候transform会立刻执行转换逻辑,而上面的两种方案就能解决这个问题。

内容的提问来源于stack exchange,提问作者ElyashivLavi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:42:53