0Pricing
Java Academy · レッスン

エラー処理と非同期 HTTP パイプライン

exceptionally、handle、whenComplete でエラーを処理し、非同期 HTTP クライアントのパイプラインを構築します。

「エラー処理と非同期 HTTP パイプライン」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

非同期エラー処理が重要な理由

非同期パイプラインでは、例外は同期コードと同じようには伝播しません。exceptionally、handle、または whenComplete を使用して、明示的にエラーを処理する必要があります。

exceptionally:エラーからの復旧

exceptionally(Function<Throwable, T>)は、future が例外で完了した場合にのみ呼び出されます。フォールバック値を提供し、パイプラインを継続させます。

CompletableFuture<String> safe = fetchUser(id)
    .thenApply(User::getName)
    .exceptionally(ex -> {
        log.warn("Fetch failed: " + ex.getMessage());
        return "Anonymous";
    });
System.out.println(safe.join()); // "Anonymous" if fetch failed

handle:成功と失敗の変換

handle(BiFunction<T, Throwable, U>)は、成功時と失敗時の両方で呼び出されます。2つの引数のいずれか一方が null になります。

fetchUser(id).handle((user, ex) -> {
    if (ex != null) return UserDto.empty();
    return UserDto.from(user);
}).thenAccept(dto -> sendResponse(dto));

whenComplete:結果にかかわらない完了後の副作用

whenComplete(BiConsumer)は、結果にかかわらず完了後に呼び出されます。結果は変更しないため、ログ記録、メトリクス、クリーンアップに使用します。

fetchUser(id)
    .whenComplete((user, ex) -> {
        if (ex != null) metrics.increment("user.fetch.error");
        else            metrics.increment("user.fetch.success");
    })
    .thenAccept(u -> sendResponse(u));

失敗した Future の再試行

失敗時に操作を再帰的に呼び出し、最大試行回数まで再試行することで、再試行ロジックを実装します。

CompletableFuture<String> withRetry(Supplier<CompletableFuture<String>> task, int retries) {
    return task.get().exceptionallyCompose(ex -> {
        if (retries > 0) {
            System.out.println("Retrying... " + retries);
            return withRetry(task, retries - 1);
        }
        return CompletableFuture.failedFuture(ex);
    });
}

Java 11 HttpClient:非同期 GET

Java 11 の HttpClientは、sendAsync()による完全非同期の HTTP 通信を提供し、CompletableFuture<HttpResponse<String>>を返します。

HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/users/1"))
    .build();
CompletableFuture<String> body = client
    .sendAsync(req, HttpResponse.BodyHandlers.ofString())
    .thenApply(HttpResponse::body);

複数の HTTP 呼び出しの連結

thenComposeを使用して依存する HTTP 呼び出しを連結します。最初にユーザーを取得し、そのユーザーの ID を使って注文を取得します。

client.sendAsync(userReq, HttpResponse.BodyHandlers.ofString())
    .thenApply(r -> parseUser(r.body()))
    .thenCompose(user -> client.sendAsync(
        buildOrdersRequest(user.getId()),
        HttpResponse.BodyHandlers.ofString()))
    .thenApply(r -> parseOrders(r.body()))
    .thenAccept(orders -> System.out.println("Orders: " + orders.size()));

allOf による並列 HTTP 呼び出し

複数のエンドポイントに並列でリクエストを送り、すべての処理が完了したらレスポンスをまとめて取得します。

List<URI> endpoints = List.of(uri1, uri2, uri3);
List<CompletableFuture<String>> requests = endpoints.stream()
    .map(uri -> client.sendAsync(
            HttpRequest.newBuilder(uri).build(),
            HttpResponse.BodyHandlers.ofString())
        .thenApply(HttpResponse::body))
    .collect(Collectors.toList());
List<String> responses = CompletableFuture
    .allOf(requests.toArray(new CompletableFuture[0]))
    .thenApply(v -> requests.stream().map(CompletableFuture::join).collect(Collectors.toList()))
    .join();

HTTP 呼び出しのタイムアウト

非同期 HTTP 呼び出しに orTimeoutを直接適用し、サーバーの応答に時間がかかりすぎた場合にキャンセルできるようにします。

CompletableFuture<String> result = client
    .sendAsync(req, HttpResponse.BodyHandlers.ofString())
    .orTimeout(5, TimeUnit.SECONDS)
    .thenApply(HttpResponse::body)
    .exceptionally(ex -> "timeout or error");

パイプラインでのステータスコード検証

thenApplyを使用して HTTP ステータスコードを確認し、エラーを示している場合はドメイン例外をスローします。これにより、パイプライン全体で一貫したエラーハンドリングを維持できます。

.thenApply(response -> {
    if (response.statusCode() != 200)
        throw new HttpResponseException(response.statusCode());
    return response.body();
})

エラー復旧とログ記録の組み合わせ

同じパイプライン内で、ログ記録には whenCompleteを、復旧には exceptionallyを組み合わせます。これらはスムーズに組み合わせて使用できます。

fetchData()
    .whenComplete((r, ex) -> { if (ex != null) log.error("Failed", ex); })
    .exceptionally(ex -> fallback())
    .thenAccept(result -> process(result));

理解度チェック

future が失敗した場合にのみ呼び出される CompletableFuture のメソッドはどれですか?

まとめ

フォールバック値には exceptionally、成功と失敗の両方の結果の変換には handle、副作用には whenCompleteを使用します。Java 11 HttpClient と thenCompose、allOfを組み合わせて、非同期 HTTP パイプラインを構築します。

よくある質問

「エラー処理と非同期 HTTP パイプライン」レッスンは無料ですか?

はい。「エラー処理と非同期 HTTP パイプライン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「エラー処理と非同期 HTTP パイプライン」で何を学びますか?

exceptionally、handle、whenComplete でエラーを処理し、非同期 HTTP クライアントのパイプラインを構築します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「エラー処理と非同期 HTTP パイプライン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. CompletableFuture の作成と完了
  2. thenApply と thenCompose による連鎖
  3. Future の結合:allOf と anyOf
  4. エラー処理と非同期 HTTP パイプライン
← Java Academyに戻る