将CompletableFutures组合成树状结构

时间:2014-06-07 03:45:40

标签: java functional-programming monads java-8

我目前正在尝试使用Java 8的Future API和Core CompleteableFuture。我知道它是一个monad,所以它应该有一个bind-Operator。

现在的想法是我有一个抽象操作k树,例如像这样:

O --- > O3 ---> O4 ---> o5
  O ---> o2 --/

我想将O3O2“合并”到新的操作O4 = (O3 o O2) (t) = O2(O3(t))中。 我的想法是,我是在O2中,并想说:将当前节点与O3合并,并返回由连接操作组成的新节点。 不幸的是,我已经尝试了一整夜,我无法弄明白。 此外,由于未知原因,使用像O1.mergeWith(O2).mergeWith(O3)之类的运算符会触发apply方法两次以进行单调调用。

目标是创建一个由其他函数组成的新函数,这样我就可以尽可能地推迟计算。

public abstract class Operation<T,R> {
  // The value a
  private final CompletableFuture<R> future;

// Executes the operation on t and returns something (maybe different) of type R
  protected abstract R apply(T t);

// Gets the value of the future of this operation
  public R get() throws Exception {
    return future.get();
  }

  protected Operation(Supplier<T> s) {
    future =  CompletableFuture.supplyAsync(s).thenApplyAsync(transform());
  }

  protected Operation(CompletableFuture<R> f) {
    future = f;
  }


  CompletableFuture<R> createTargetFuture(R _value) {
    return CompletableFuture.supplyAsync(() -> _value);
  }

  <S> Operation<T,S> mergeWith(Operation<R,S> _other) {
    CompletableFuture<S> _result = future.thenComposeAsync(
      // Method is synchronous, but is run async :) We need the createTargetFuture,         otherwise we cannot turn the constant t into a producer.
      (t) -> _other.createTargetFuture(_other.apply(t)));
      //transform()).thenApplyAsync(_other.transform());
    return new Operation<T, S>(_result) {
      @Override
      protected S apply(T t) {
        // What to put here
        return null;
      }
    };
  }

  protected Function<T,R> transform(){
    return this::apply;
  }
}

1 个答案:

答案 0 :(得分:2)

你想要实现的目标并不是很清楚。您的整个Operation课程似乎都在为CompletableFuture添加一个已经提供的功能。

如果您有Supplier<T> s并希望推迟执行,则可以按照您已知的方式CompletableFuture.supplyAsync(s)进行操作。

现在,如果您要将Function<T,R> f应用于CompletableFuture<T> a的推迟结果,只需使用CompletableFuture.supplyAsync(()->f.apply(a.join()))

同样适用于两个CompletableFuture和一个BiFunctionCompletableFuture.supplyAsync(()->f.apply(a.join(),b.join()))

如果您需要将操作包装在某种支持代码中,可以创建如下的实用程序方法:

public static <T> CompletableFuture<T> create(Supplier<T> s) {
    return CompletableFuture.supplyAsync(s);
}
public static <T,R> CompletableFuture<R> create(
  Function<T,R> f, CompletableFuture<T> a) {
    return CompletableFuture.supplyAsync(()->f.apply(a.join()));
}
public static <T,U,R> CompletableFuture<R> create(
  BiFunction<T,U,R> f, CompletableFuture<T> a, CompletableFuture<U> b) {
    return CompletableFuture.supplyAsync(()->f.apply(a.join(),b.join()));
}

然后您可以愉快地执行异步操作,例如:

int i=create((a,b)->a+b, create(()->42),create(()->100)).join();

但是,当然,同样的事情也可以在没有任何支持方法的情况下发挥作用:

int i=CompletableFuture.supplyAsync(() ->
    CompletableFuture.supplyAsync(()->42).join()
  + CompletableFuture.supplyAsync(()->100).join() ).join();

int j=CompletableFuture.supplyAsync(()->42).thenApplyAsync(
    a-> a + CompletableFuture.supplyAsync(()->100).join() ).join();