【异步函数式编程】CompletableFuture用法(二)

814 阅读2分钟

继上章节(传送门>>>),本章继续介绍CompletableFuture其他方法的使用。

public static void main(String[] args) throws Exception {
    // 6. 回调2.0【whenComplete,handle】
    CompletableFuture<String> cf4 = CompletableFuture.supplyAsync(() -> {
        System.out.println("6.业务过程=" + 1 / 1);
        // System.out.println("6.业务过程=" + 1 / 0);
        return "cf4正常执行返回";
    }).whenComplete((result, exce) -> {
        if (null != exce) {
            // exce.printStackTrace();
            System.out.println("异常信息=" + exce.getMessage());
        } else {
            System.out.println("6.回调2.0正常执行返回");
        }
    });
    System.out.println(cf4.get());
    /**
    * 注: 和之前回调应用场景的区别 
    * 1.cf4任务是正常执行的,cf4.get()的结果就是cf4执行的结果
    * 2.cf4任务是执行异常的,则cf4.get()会抛出异常
    * 
    * handle与whenComplete用法类似,区别: 
    * 1:handle有返回值,whenComplete无返回值
    * 2:handle有返回值且与cf4自身的返回无任何关系
    */

    // 7.组合处理(1)【thenCombine、thenAcceptBoth、runAfterBoth】
    /**
    * 三个方法都是将两个CompletableFuture组合起来,两个都正常执行完了才会执行某个任务 
    * 区别:
    * 1:thenCombine会将两个任务的返回值作为入参传递到目标方法中,且目标方法有返回值
    * 2:thenAcceptBoth同样将两个任务的返回值作为目标方法入参,但目标方法无返回值 
    * 3:runAfterBoth没有入参,也没有返回值
    */
    CompletableFuture<String> cf5_1 = CompletableFuture.supplyAsync(() -> {
        // 任务1
        return "cf5_1返回";
    });
    CompletableFuture<String> cf5_2 = CompletableFuture.supplyAsync(() -> {
        // 任务2
        return "cf5_2返回";
    });

    CompletableFuture<String> cf5_thenCombine = cf5_1.thenCombine(cf5_2, (a, b) -> {
        // 有返回
        return "7.组合处理【thenCombine】=" + a + " -- " + b;
    });
    System.out.println(cf5_thenCombine.get());

    CompletableFuture<Void> cf5_thenAcceptBoth = cf5_1.thenAcceptBoth(cf5_2, (a, b) -> {
        // 无返回
        System.out.println("7.组合处理【thenAcceptBoth】=" + a + " -- " + b);
    });
    cf5_thenAcceptBoth.get();
    CompletableFuture<Void> cf5_runAfterBoth = cf5_1.runAfterBoth(cf5_2, () -> {
        // 无入参,无返回
        System.out.println("7.组合处理【runAfterBoth】=" + "无入参,无返回");
    });
    cf5_runAfterBoth.get();

    // 7.组合处理(2)【applyToEither、acceptEither、runAfterEither】
    /**
    * 三个方法都是将两个CompletableFuture组合起来,只要其中一个执行完了就会执行目标任务 
    * 区别:
    * 1:applyToEither会将已经执行完成的任务的执行结果作为方法入参,并有返回值;
    * 2:acceptEither同样将已经执行完成的任务的执行结果作为方法入参,但是没有返回值 
    * 3:runAfterEither没有方法入参,也没有返回值
    */
    // 7.组合处理(1)和7.组合处理(2)的区别在于,执行目标任务的前提,前者必须全部正常执行,后者有一个执行完成

    // 8.【allOf、anyOf】
    CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        return "Task1";
    });
    CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
        }
        return "Task2";
    });
    CompletableFuture<String> task3 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2500);
        } catch (InterruptedException e) {
        }
        return "Task3";
    });

    // 可以类似实现countdownLatch的功能,实现阻塞线程,等待子任务执行完成
    CompletableFuture<Void> cf6 = CompletableFuture.allOf(task1, task2, task3);
//		System.out.println(cf6.get(20, TimeUnit.MILLISECONDS));
    System.out.println("cf6.get()=" + cf6.get());
    /**
    * 区别:
    * 1:allof等待所有任务执行完成才执行cf6
    * 2:anyOf是只有一个任务执行完成,无论是正常执行或者执行异常,都会执行cf6
    */
    // allof:如果有一个任务异常终止,则cf6.get时会抛出异常,都是正常执行,cf6.get返回null
    // anyOf:cf6.get的结果就是已执行完成的任务的执行结果
}

执行结果如图:

image.png 欢迎评论区指正和交流。