2016-11-24 87 views
2

我是新來的CompletableFuture,我想調用一個方法MetadataLoginUtil :: login可以拋出異常。但是,下面的代碼並沒有被編譯,雖然我寫了'異常'。它說,我必須在嘗試& catch中包裝MetadataLoginUtil :: login。嘗試與抓住時調用supplyAsync

請指教。 謝謝!

public void run() throws ConnectionException { 
     CompletableFuture<Void> mt = CompletableFuture.supplyAsync(MetadataLoginUtil::login).exceptionally(e -> {System.out.println(e); return null; }).thenAccept(e -> System.out.println(e)); 
} 

回答

1

CompletableFuture.supplyAsync(Supplier<U>)需要一個java.util.function.Supplier<U>實例,Supplier.get()方法的簽名不允許檢查的異常。要清楚地看到這一點,請注意CompletableFuture.supplyAsync(MetadataLoginUtil::login)相當於

CompletableFuture<Void> mt = CompletableFuture.supplyAsync(new Supplier<Void>() { 
     @Override 
     public Void get() { 
      return MetadataLoginUtil.login(); 
     } 
    }) 

顯然無法編譯。

可以處理這個異常的Supplier內,改變CompletableFuture.supplyAsync(MetadataLoginUtil::login).exceptionally(e -> {System.out.println(e); return null; })

CompletableFuture.supplyAsync(() -> { 
     try { 
      return MetadataLoginUtil.login(); 
     } catch (Exception e) { 
      System.out.println(e); 
      return null; 
     } 
    }) 

這不是很漂亮,但CompletableFuture的API似乎不使用checked異常很好地工作。

+1

謝謝,那麼'異常'的意義是什麼?我不明白爲什麼我們需要這個 – sfdcdev

+0

問題是,完整的lambda原則根本不包括檢查的異常。不過,您可以異常使用或處理RuntimeException及其派生。一種非常常見的模式是,在運行時異常中將lambda包裝爲異常並重新拋出:catch(Exception e){throw new RuntimeException(e); } – mtj

+1

@mtj:lambdas和異常一起工作;這只是接口聲明的問題。你甚至可以使接口的異常類型參數聲明方法精確地拋出提供的函數參數可能拋出的東西。然而,這在API的固定版本不適用於早期的Java 8編譯器版本。 – Holger

5

這不是CompletableFuture一般工作方式的缺陷,而是便利方法的一個缺陷,它們都使用不允許檢查異常的功能接口。你可以用另一種方法supplyAsync解決這個問題:

public static <T> CompletableFuture<T> supplyAsync(Callable<T> c) { 
    CompletableFuture<T> f=new CompletableFuture<>(); 
    CompletableFuture.runAsync(() -> { 
     try { f.complete(c.call()); } catch(Throwable t) { f.completeExceptionally(t); } 
    }); 
    return f; 
} 

這基本上是做一樣的原始supplyAsync,但允許檢查的異常。因此,您可以像原始嘗試一樣使用它,只需重定向最初的supplyAsync電話。

CompletableFuture<Void> mt = supplyAsync(MetadataLoginUtil::login) 
    .exceptionally(e -> { System.out.println(e); return null; }) 
    .thenAccept(e -> System.out.println(e));