Дослідження асинхронного програмування з CompletableFuture в Java

В сучасних додатках, особливо при роботі з операціями, пов'язаними з ввід/виводом, такими як запити до бази даних, операції з файлами або HTTP запити, асинхронне виконання завдань може покращити продуктивність, дозволяючи системі виконувати кілька операцій одночасно без блокування. У Java CompletableFuture є потужним інструментом для написання асинхронного, неблокуючого коду.

У цій статті ми розглянемо кілька прикладів використання CompletableFuture в різних сценаріях, що дозволяє зробити ваші додатки більш ефективними, використовуючи асинхронне виконання.

1. thenAcceptAsync - Виконання дії після завершення

Метод thenAcceptAsync використовується, коли ви хочете виконати дію (наприклад, надіслати сповіщення) після завершення асинхронної задачі. Дія буде виконана в окремому потоці.

public static void thenAcceptAsyncExample() {  
    CompletableFuture userProfileFuture = CompletableFuture.supplyAsync(() -> {  
        sleep(1000);  
        return "User: John Doe, Email: [email protected]";  
    });  

    userProfileFuture.thenAcceptAsync(userProfile -> {  
        System.out.println("Sending email notification to: " + userProfile);  
    });  
}

2. thenRun - Виконання дії без використання результату

Іноді вам не потрібен результат асинхронної задачі, але ви все одно хочете виконати дію після її завершення. thenRun дозволяє виконати задачу після завершення іншої без використання її результату.

public static void thenRunExample() {  
    CompletableFuture orderDetails = CompletableFuture.supplyAsync(() -> {  
        sleep(1000);  
        System.out.println("Fetched order details for a phone.");  
        return "OrderDetails for Phone";  
    });  

    userDetails.thenRun(() -> {  
        System.out.println("Logging: Order details fetched successfully.");  
    });  
}

3. thenRunAsync - Виконання дії асинхронно

Метод thenRunAsync працює подібно до thenRun, але виконує наступну дію в окремому потоці, що може бути корисним для незалежних задач, які можуть виконуватись одночасно.

public static void thenRunAsyncExample() {  
    CompletableFuture orderDetails = CompletableFuture.supplyAsync(() -> {  
        sleep(1000);  
        System.out.println("Fetched order details for a phone.");  
        return "OrderDetails for Phone";  
    });  

    userDetails.thenRunAsync(() -> {  
        System.out.println("Sending information email to user...");  
    });  
}

4. thenCombineAsync - Комбінування результатів двох Future

thenCombineAsync корисний, коли вам потрібно об'єднати результати двох незалежних асинхронних задач. Логіка об'єднання виконується асинхронно.

public static void thenCombineAsyncExample() {  
    CompletableFuture weatherForecast = CompletableFuture.supplyAsync(() -> {  
        sleep(500);  
        return "Sunny, 25°C";  
    });  

    CompletableFuture userLocation = CompletableFuture.supplyAsync(() -> {  
        sleep(300);  
        return "Istanbul";  
    });  

    CompletableFuture weatherReport = weatherForecast.thenCombineAsync(userLocation,  
        (forecast, location) -> "Weather in " + location + ": " + forecast);  

    weatherReport.thenAccept(System.out::println);  
}

5. thenApplyAsync - Перетворення результату асинхронно

Якщо вам потрібно перетворити результат асинхронної задачі, ви можете використовувати thenApplyAsync. Цей метод застосовує функцію до результату асинхронно і повертає новий CompletableFuture з перетвореним результатом.

public static void thenApplyAsyncExample() {  
    CompletableFuture productDetails = CompletableFuture.supplyAsync(() -> {  
        sleep(2000);  
        return "Product: Smartphone, Price: $799";  
    });  

    CompletableFuture promoMessage = productDetails.thenApplyAsync(details ->  
        "Limited time offer! " + details + " - Get it now!");  

    promoMessage.thenAccept(System.out::println);  
}

thenCompose - Ланцюжок залежних асинхронних задач

Коли у вас є залежні завдання (друге завдання залежить від результату першого), ви можете використовувати `thenCompose`. Це дозволяє з'єднувати асинхронні задачі в ланцюжок.

public static void thenComposeExample() {
CompletableFuture productInfo = getProductInfo("Phone")
.thenCompose(CompletableFutureExamples::getCustomerReviews);

productInfo.thenAccept(System.out::println);  

}
```

7. Обробка виключень: exceptionally та handle

Асинхронні задачі можуть не виконуватись, тому важливо обробляти виключення. Ви можете використовувати exceptionally для обробки виключень та надання значення за замовчуванням, або використовувати handle для обробки як результату, так і будь-яких виключень.

public static void exceptionallyCF() {  
    CompletableFuture.supplyAsync(() -> {  
        throw new RuntimeException("Product not found!");  
    })  
    .exceptionally(ex -> "Error: " + ex.getMessage())  
    .thenAccept(System.out::println);  
}  

public static void handleCF() {  
    CompletableFuture.supplyAsync(() -> {  
        throw new RuntimeException("Error!");  
    })  
    .handle((result, ex) -> ex != null ? "Recovered from: " + ex.getMessage() : result)  
    .thenAccept(System.out::println);  
}

8. thenCombine - Комбінування результатів кількох задач

Ви можете комбінувати результати кількох задач за допомогою thenCombine. Це особливо корисно, коли вам потрібно зібрати дані з кількох джерел і прийняти рішення на основі комбінованих результатів.

public static void combineCF() {  
    CompletableFuture ordersFuture = getUserOrdersAsync("12345");  
    CompletableFuture loyaltyPointsFuture = getLoyaltyPointsAsync("12345");  
    CompletableFuture discountFuture = getCurrentDiscountAsync("12345");  

    CompletableFuture combinedFuture = ordersFuture  
        .thenCombine(loyaltyPointsFuture, (orders, loyaltyPoints) -> {  
            System.out.println("User Orders: " + orders);  
            System.out.println("Loyalty Points: " + loyaltyPoints);  
            return loyaltyPoints;  
        })  
        .thenCombine(discountFuture, (loyaltyPoints, discount) -> {  
            String recommendation = makeRecommendation(loyaltyPoints, discount);  
            return recommendation;  
        })  
        .thenAccept(finalRecommendation -> {  
            System.out.println("Personalized Recommendation: " + finalRecommendation);  
        });  

    combinedFuture.join();  
}

9. Використання ExecutorService для синхронного виконання

Для деяких завдань ви можете захотіти заблокувати основний потік до того, як буде отриманий результат. ExecutorService дає гнучкість для подачі задач, які повертають результат синхронно.

Future.get() блокує потік до завершення обчислень. Це корисно, коли вам потрібно почекати результат синхронно.

public static void executorService() throws ExecutionException, InterruptedException {  
    ExecutorService executorService = Executors.newCachedThreadPool();  
    Future future = executorService.submit(() -> {  
        sleep(5000);  
        return 100;  
    });  

    Integer orderValue = future.get();  
    System.out.println("Order value: " + orderValue);  
    executorService.shutdown();  
}

10. Використання CompletableFuture.supplyAsync для асинхронного виконання

Якщо ви хочете виконати задачу асинхронно без блокування основного потоку, CompletableFuture.supplyAsync є ідеальним варіантом для таких сценаріїв.

public static void executorServiceWithCFSupplyAsync() throws ExecutionException, InterruptedException {  
    CompletableFuture voidCompletableFuture = CompletableFuture.supplyAsync(() -> {  
        sleep(5000);  
        return 100;  
    }).thenAccept(result -> System.out.println("Order value: " + result));  
}

pic

Висновок

CompletableFuture надає потужний інструмент для написання асинхронного, неблокуючого коду в Java.
Використовуючи різні методи, такі як thenAcceptAsync, thenRun, thenCombineAsync та обробка виключень, ви можете значно покращити продуктивність і чуйність ваших додатків.

У цій статті ми розглянули кілька прикладів, які допоможуть вам почати працювати з асинхронним програмуванням у Java, використовуючи CompletableFuture. Розуміння та застосування цих концепцій може допомогти вам створювати більш масштабовані та ефективні системи.

Перекладено з: Exploring Asynchronous Programming with CompletableFuture in Java

Leave a Reply

Your email address will not be published. Required fields are marked *