2016-11-21 98 views
2

我試圖返回一個CompletableFuture,它將返回來自Amazon的響應。我的代碼首先檢查是否響應緩存在本地。如果是這樣,它會返回響應,否則會調用亞馬遜。 [注意:真正的版本也會緩存從亞馬遜收到的響應,但我沒有包括,因爲代碼已經非常複雜。]避免複製CompletableFuture的狀態

有沒有辦法改變我的callAmazon方法的實現方法重新組織代碼),以便我不必「手動」將響應狀態從amazonApi複製到finalResponse?我不想直接返回cacheCheck,因爲我不希望調用者能夠complete()它。

public CompletableFuture<Response> fetchProductList() { 
    CompletableFuture<Response> finalResponse = new CompletableFuture<>(); 
    CompletableFuture<Response> cacheCheck = //... 

    // First, see if we have a cached copy 
    cacheCheck.whenComplete((response, throwable) -> { 
     if (throwable == null) { 
      // Cache hit. Return the cached response 
      finalResponse.complete(response); 
     } else { 
      // Cache miss. Call Amazon 
      callAmazon(finalResponse); 
     } 
    }); 
    return finalResponse; 
} 

private void callAmazon(CompletableFuture<Response> finalResponse) { 
    CompletableFuture<Response> amazonApi = //... 
    amazonApi.whenComplete((response, throwable) -> { 
     // Copy the state to the `finalResponse` 
     if (throwable == null) { 
      finalResponse.complete(response); 
     } else { 
      finalResponse.completeExceptionally(throwable); 
     } 
    }); 
} 
+0

退房.thenCompose:http://download.java.net/lambda/b88/docs/api/java/util/concurrent/CompletableFuture.html#thenCompose(java.util.function.Function) –

+0

嗨亞歷杭德羅,我試圖想在這種情況下如何使用「組合」,但我無法理解它的工作原理。我不認爲你可以勾畫出一些代碼嗎? –

+0

爲什麼你打擾調用者調用'complete()'?你打算在幾次通話之間分享這個'CompletableFuture'嗎?無論如何,您可以通過返回一個['CompletionStage'](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html)來輕鬆地隱藏該方法(而不是'toCompletableFuture ()'將取消隱藏它)。 –

回答

0

什麼讓你的要求如此複雜是因爲cacheCheck可以拋出一個異常。

在你的情況下,我會做的是重構高速緩存,以便在高速緩存中找不到該值時提供null,或者如果值位於高速緩存中,則實際爲Response

此外,我將修改callAmazon直接返回CompletableFuture

private CompletableFuture<Response> callAmazon() { 
    CompletableFuture<Response> amazonApi = //... 
    return amazonApi; 
} 

這樣,您就可以使用thenCompose

final CompletableFuture<Response> cacheCheck = //... 
final CompletableFuture<Response> amazonResponse = callAmazon(); 

final CompletableFuture<Response> finalResult = 
     cachedResponse.thenCompose(cacheResult -> { 
      return cacheResult == null ? amazonResponse : CompletableFuture.completedFuture(cacheResult); 
    }); 

如果你真的需要從緩存中拋出一個異常,您可以使用exceptionally將該異常轉換爲空值,然後使用thenCompose來決定是使用緩存值還是調用Amazon:

final CompletableFuture<Response> finalResult = cachedResponse.exceptionally(e -> { 
     return null; 
    }).thenCompose(cacheResult -> { 
     return cacheResult == null ? amazonResponse : CompletableFuture.completedFuture(cacheResult); 
    });