如何在java中实现更改输出类型的承诺

如何在java中实现更改输出类型的承诺,java,promise,Java,Promise,我试图用java实现一个简单的promise系统。我这样做是为了特殊目的,所以请不要推荐任何图书馆 当我尝试实现一个thenApply()方法时,我遇到了一个问题,该方法将函数作为参数,类似于have,因此返回另一种类型的承诺 承诺界面: public interface Promise<T> { Promise<T> then(Consumer<T> handler); <U> Promise<U> thenAppl

我试图用java实现一个简单的promise系统。我这样做是为了特殊目的,所以请不要推荐任何图书馆

当我尝试实现一个
thenApply()
方法时,我遇到了一个问题,该方法将函数作为参数,类似于have,因此返回另一种类型的承诺

承诺界面:

public interface Promise<T> {
    Promise<T> then(Consumer<T> handler);

    <U> Promise<U> thenApply(Function<T, U> handler);
}
公共接口承诺{
然后承诺(消费者处理人);
承诺然后应用(函数处理程序);
}
我迄今为止的执行情况:

public class PromiseImpl<T> implements Promise<T> {

    private List<Consumer<T>> resultHandlers = new ArrayList<>();

    public PromiseImpl(CompletableFuture<T> future) {
        future.thenAccept(this::doWork);
    }

    @Override
    public Promise<T> then(Consumer<T> handler) {
        resultHandlers.add(handler);
        return this;
    }

    @Override
    public <U> Promise<U> thenApply(Function<T, U> handler) {
        // How to implement here??? I don't have the result yet
        handler.apply(?);
    }

    private void onResult(T result) {
        for (Consumer<T> handler : resultHandlers) {
            handler.accept(result);
        }
    }

    private Object doWork(T result) {
        onResult(result);
        return null;
    }
}
公共类PromiseImpl实现承诺{
private List resultHandlers=new ArrayList();
公共承诺(可完成的未来){
然后接受(这个::工作);
}
@凌驾
公众承诺(消费者处理人){
添加(处理程序);
归还这个;
}
@凌驾
公共承诺然后应用(函数处理程序){
//如何在这里实施???我还没有结果
处理程序。应用(?);
}
私有void onResult(T result){
for(使用者处理程序:ResultHandler){
接受(结果);
}
}
私有对象工作(T结果){
onResult(result);
返回null;
}
}
问题是我不知道我最初在
thenApply()
方法中的结果,因此我无法调用我的处理程序。另外,我不想调用
future.get()
,因为这个方法是阻塞的


我如何才能做到这一点?

您可以返回一些匿名类,该类扩展PromiseImpl并重写onResult,以便处理程序接受应用映射器函数的结果。不要忘记调用父onResult,以便调用父处理程序

真正的问题在于你的
Promise
类型的设计。它持有一组回调,所有回调都将在完成时调用。这是一个基本问题(围绕
然后apply
函数的返回类型限制通用功能)。这可以通过更改
Promise
实现来解决,即在注册处理程序时返回
new
Promise,而不是返回
This
,这样每个Promise对象都将有自己的处理程序来调用

除了解决这个问题之外,它还是一个更好的函数式编程设计,因为您可以使您的
Promise
对象不可变

我会将界面更改为:

interface Promise<T> {
    <U> Promise<U> thenApply(Function<T, U> handler);
    Promise<Void> thenAccept(Consumer<T> consumer);
}
使用它可以非常简单:

Promise<String> stringPromise = new PromiseImpl<>(new CompletableFuture<String>());
Promise<Long> longPromise = stringPromise.thenApply(str -> Long.valueOf(str.length()));
Promise<Void> voidPromise = stringPromise.thenAccept(str -> System.out.println(str));
并通过以下方式实施:

public T get() {
    //try-catch 
    return this.future.get();
}
注意:这看起来越来越像是对
CompletableFuture
的复制,这就提出了一个问题:为什么要这样做。但是假设在这个接口中会有其他类似于Promise的方法,那么这个方法将包装未来的API


如果需要将同一个
Promise
对象与回调列表一起使用,则别无选择,只能使用
函数
具体类型参数对
Promise
接口进行参数化:

public interface Promise<T, U>
公共接口承诺

如果您想保持类的其余部分不变并只实现
然后应用
方法,
U
将不能成为
然后
然后应用
上的方法泛型参数,您必须创建一个新的
可完成的未来
,因为这是您当前构建新的
承诺的唯一方法:

@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
    CompletableFuture<U> downstream = new CompletableFuture<>();
    this.then(t -> downstream.complete(handler.apply(t)));
    return new PromiseImpl<>(downstream);
}

但是,如果您想在
CompletableFuture
之上实现自己的API,您真正应该做的是使用decorator模式,并将
CompletableFuture
实例包装为
PromiseImpl
中的私有变量,因为类型可能不兼容,我认为此解决方案不起作用。考虑<代码>字符串< /代码>和<代码>整数< /代码>类型。如果你认为我错了,请提供一个代码示例。你没有指定你希望
然后应用
实际执行的操作…@Michael与
然后
方法相同,但是使用另一种返回类型,你打算如何获取返回值<代码>承诺
没有这样做的方法。但是
然后接受
是否应该返回一个
承诺
?对于
承诺
,我能实际做些什么?为什么不仅仅是
void
?@Michael我为“如何检索值”编辑了这篇文章,但这本质上是关于使用未来实例的<除非
Promise
接口中增加了更多的方法,例如检查状态,即使没有返回值,否则code>Promise
也不会有用(这将类似于<代码>完整的未来< /代码>。我假设问题中的接口版本被简化了。否则,我真的不明白为什么一个人不能只使用<代码>完整的未来<代码>。@ EnnistkKiWele认为我不是java 8,这意味着我不能使用<代码>完整的未来< /代码>。我只是使用了<代码>pletableFuture
作为一种简单的方法来表明存在某种延迟操作。我的错,我应该在问题中提到这一点。@flash绝对,你可以有很多很好的理由这样做,而不是争论这一点。但是,在Java8之前,我们的
Future
接口更差,实现了
FutureTask
它。我想说的是,我们应该假设你有很好的理由来实现这个…:-)@ErnestKiwele抱歉,今天不是我最好的一天。我仍然被卡住了。未来任务的实现会发生什么变化?它确实有一个
get
方法,但这会阻止
然后apply
方法,对吗?
public interface Promise<T, U>
@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
    CompletableFuture<U> downstream = new CompletableFuture<>();
    this.then(t -> downstream.complete(handler.apply(t)));
    return new PromiseImpl<>(downstream);
}
@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
    PromiseImpl result = new PromiseImpl();
    this.then(t -> result.doWork(handler.apply(t)));
    return result;
}