Java Language
完了可能な将来
サーチ…
前書き
CompletableFutureは、Java SE 8に追加されたクラスであり、Java SE 5のFutureインタフェースを実装しています。Futureインタフェースをサポートするだけでなく、将来の完了時に非同期コールバックを可能にする多くのメソッドが追加されています。
ブロックメソッドを非同期に変換する
次の方法では、Webページを取得してテキストの長さを数えるために、接続に応じて2〜2秒かかります。どんなスレッドが呼び出されても、それはその期間中ブロックされます。また、後で便利な例外が返されます。
public static long blockingGetWebPageLength(String urlString) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(urlString).openConnection().getInputStream()))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString().length();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
これは、ブロッキングメソッド呼び出しを別のスレッドに移動することによってすぐに戻るメソッドに変換します。デフォルトでは、supplyAsyncメソッドは共通プールでサプライヤを実行します。私はオプションのサービスパラメータを追加した理由は、プール内のスレッドを使い果たしているかもしれないので、これはブロッキングメソッドのために、おそらく良い選択ではありません。
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
非同期ファンクションで関数を使用するには、thenAcceptなどの完了時に、サプライヤの結果で呼び出されるlamdaを受け入れるメソッドを使用する必要があります。また、発生した可能性のある例外を記録するために、例外的に使用するか、またはメソッドを処理することも重要です。
public static void main(String[] args) {
asyncGetWebPageLength("https://stackoverflow.com/")
.thenAccept(l -> {
System.out.println("Stack Overflow returned " + l);
})
.exceptionally((Throwable throwable) -> {
Logger.getLogger("myclass").log(Level.SEVERE, "", throwable);
return null;
});
}
CompletableFutureの簡単な例
以下の例では、 calculateShippingPrice
メソッドは、処理時間を要する出荷コストを計算します。実際の例では、これは、例えば、製品の重量と出荷方法に基づいて価格を返す別のサーバに連絡することである。
CompletableFuture
を介してこれを非同期的にモデリングすることで、このメソッドで異なる作業を続けることができます(つまり、パッケージング費用の計算)。
public static void main(String[] args) {
int price = 15; // Let's keep it simple and work with whole number prices here
int weightInGrams = 900;
calculateShippingPrice(weightInGrams) // Here, we get the future
.thenAccept(shippingPrice -> { // And then immediately work on it!
// This fluent style is very useful for keeping it concise
System.out.println("Your total price is: " + (price + shippingPrice));
});
System.out.println("Please stand by. We are calculating your total price.");
}
public static CompletableFuture<Integer> calculateShippingPrice(int weightInGrams) {
return CompletableFuture.supplyAsync(() -> {
// supplyAsync is a factory method that turns a given
// Supplier<U> into a CompletableFuture<U>
// Let's just say each 200 grams is a new dollar on your shipping costs
int shippingCosts = weightInGrams / 200;
try {
Thread.sleep(2000L); // Now let's simulate some waiting time...
} catch(InterruptedException e) { /* We can safely ignore that */ }
return shippingCosts; // And send the costs back!
});
}