Асинхронные запросы
sendAsync и CompletableFuture
«Асинхронные запросы» — бесплатный урок Java Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Асинхронные запросы
Блокировка потока при каждом HTTP-вызове приводит к неэффективному использованию потоков. HTTP-клиент JDK предоставляет sendAsync, который немедленно возвращает CompletableFuture и выполняет работу в фоновом потоке выполнения.
Это позволяет одновременно отправлять множество запросов и объединять их результаты без ручного управления потоками.
send и sendAsync
Сигнатуры различаются возвращаемым значением:
- send возвращает
HttpResponse<T>и блокирует поток, объявляяIOExceptionиInterruptedException. - sendAsync возвращает
CompletableFuture<HttpResponse<T>>и никогда не блокирует поток; ошибки передаются через этот объект.
Простой вызов sendAsync
sendAsync принимает тот же запрос и BodyHandler, что и send. Возвращаемый объект завершается, когда ответ готов.
import java.net.URI;
import java.net.http.*;
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com"))
.build();
CompletableFuture<HttpResponse<String>> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Request sent, future created");
}
}Преобразование с помощью thenApply
Используйте thenApply, чтобы преобразовать результат после его получения — например, извлечь тело из ответа.
Этот код выполняется синхронно в потоке, завершившем предыдущий этап.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) throws Exception {
CompletableFuture<String> future =
CompletableFuture.completedFuture("OK 200")
.thenApply(body -> "Length=" + body.length());
System.out.println(future.get());
}
}Обработка с помощью thenAccept
Если требуется только побочный эффект и возвращаемое значение не нужно, используйте thenAccept. Он принимает Consumer и возвращает CompletableFuture<Void>.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) throws Exception {
CompletableFuture<Void> done =
CompletableFuture.completedFuture("payload")
.thenAccept(b -> System.out.println("Received: " + b));
done.get();
}
}Ожидание с помощью join
Чтобы дождаться асинхронного результата из main, вызовите join() (без проверки) или get() (с проверкой). В настоящем сервере следует объединять этапы, а не блокировать поток.
join() оборачивает сбои в непроверяемое CompletionException.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
CompletableFuture<Integer> f =
CompletableFuture.supplyAsync(() -> 21).thenApply(n -> n * 2);
int result = f.join();
System.out.println("Result: " + result);
}
}Обработка ошибок с помощью exceptionally
exceptionally предоставляет резервное значение, если этап завершился с ошибкой, восстанавливая конвейер.
Так асинхронный поток выполнения HTTP-запроса не прекращается из-за сетевой ошибки.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
CompletableFuture<String> f = CompletableFuture
.<String>supplyAsync(() -> { throw new RuntimeException("boom"); })
.exceptionally(ex -> "fallback: " + ex.getMessage());
System.out.println(f.join());
}
}Объединение двух запросов
thenCombine ожидает завершения двух независимых асинхронных результатов и объединяет их. При асинхронной работе с HTTP это позволяет параллельно получить данные из двух конечных точек и объединить тела ответов.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> b = CompletableFuture.supplyAsync(() -> "World");
String combined = a.thenCombine(b, (x, y) -> x + " " + y).join();
System.out.println(combined);
}
}Параллельный запуск множества запросов
Чтобы выполнить набор запросов, соберите каждый объект CompletableFuture в список, а затем используйте CompletableFuture.allOf(...), чтобы дождаться завершения всех запросов.
allOf возвращает CompletableFuture<Void>; отдельные результаты считываются после этого.
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
List<CompletableFuture<Integer>> futures = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
int n = i;
futures.add(CompletableFuture.supplyAsync(() -> n * n));
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
for (var f : futures) System.out.println(f.join());
}
}Итоги асинхронного шаблона
Типичный конвейер асинхронных HTTP-операций выглядит так:
client.sendAsync(req, BodyHandlers.ofString()).thenApply(HttpResponse::body)для получения тела.thenAccept(System.out::println)для его обработки.exceptionally(ex -> ...)для восстановления после ошибки
Ожидание сети никогда не блокирует поток.
Когда выбирать асинхронность
Выбирайте sendAsync, когда выполняете много параллельных вызовов, обращаетесь к нескольким службам или работаете внутри реактивного/неблокирующего сервера. Выбирайте send для простых скриптов и разовых вызовов, где блокировка допустима.
Быстрая проверка
Проверьте, насколько хорошо вы поняли работу с асинхронными запросами.
Итоги
Вы научились выполнять неблокирующие HTTP-вызовы:
- sendAsync возвращает
CompletableFutureвместо блокировки. - thenApply / thenAccept преобразуют результат и обрабатывают его.
- exceptionally предоставляет резервное значение при сбое.
- thenCombine объединяет два параллельных вызова; allOf ожидает завершения набора запросов.
- Асинхронный подход подходит для высококонкурентных и реактивных серверов, а синхронный — для простых скриптов.
Изучай Java с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 104
- Уроки
- 374
Часто задаваемые вопросы
Урок «Асинхронные запросы» бесплатный?
Да — полный текст урока «Асинхронные запросы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Асинхронные запросы»?
sendAsync и CompletableFuture Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Асинхронные запросы»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- java.net.http.HttpClient
- Асинхронные запросы
- Тела запросов и заголовки
- Обработка ответов