Java8新的異步編程方式 CompletableFuture(三)

前面兩篇文章已經整理了CompletableFuture大部分的特性,本文會整理完CompletableFuture余下的特性,以及將它跟RxJava進行比較。

3.6 Either

Either 表示的是兩個CompletableFuture,當其中任意一個CompletableFuture計算完成的時候就會執行。

方法名描述
acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)當任意一個CompletableFuture完成的時候,action這個消費者就會被執行。
acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)當任意一個CompletableFuture完成的時候,action這個消費者就會被執行。使用ForkJoinPool
acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor)當任意一個CompletableFuture完成的時候,action這個消費者就會被執行。使用指定的線程池
        Random random = new Random();CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future2";});CompletableFuture<Void> future =  future1.acceptEither(future2,str->System.out.println("The future is "+str));try {future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}復制代碼

執行結果:The future is from future1 或者 The future is from future2。
因為future1和future2,執行的順序是隨機的。

applyToEither 跟 acceptEither 類似。

方法名描述
applyToEither(CompletionStage<? extends T> other, Function<? super T,U> fn)當任意一個CompletableFuture完成的時候,fn會被執行,它的返回值會當作新的CompletableFuture<U>的計算結果。
applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn)當任意一個CompletableFuture完成的時候,fn會被執行,它的返回值會當作新的CompletableFuture<U>的計算結果。使用ForkJoinPool
applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn, Executor executor)當任意一個CompletableFuture完成的時候,fn會被執行,它的返回值會當作新的CompletableFuture<U>的計算結果。使用指定的線程池
        Random random = new Random();CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future2";});CompletableFuture<String> future =  future1.applyToEither(future2,str->"The future is "+str);try {System.out.println(future.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}復制代碼

執行結果也跟上面的程序類似。

3.7 其他方法

allOf、anyOf是CompletableFuture的靜態方法。

3.7.1 allOf

方法名描述
allOf(CompletableFuture<?>... cfs)在所有Future對象完成后結束,并返回一個future。

allOf()方法所返回的CompletableFuture,并不能組合前面多個CompletableFuture的計算結果。于是我們借助Java 8的Stream來組合多個future的結果。

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "tony");CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "cafei");CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "aaron");CompletableFuture.allOf(future1, future2, future3).thenApply(v ->Stream.of(future1, future2, future3).map(CompletableFuture::join).collect(Collectors.joining(" "))).thenAccept(System.out::print);復制代碼

執行結果:

tony cafei aaron復制代碼

3.7.2 anyOf

方法名描述
anyOf(CompletableFuture<?>... cfs)在任何一個Future對象結束后結束,并返回一個future。
        Random rand = new Random();CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(rand.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(rand.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future2";});CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(rand.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future3";});CompletableFuture<Object> future =  CompletableFuture.anyOf(future1,future2,future3);try {System.out.println(future.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}復制代碼

使用anyOf()時,只要某一個future完成,就結束了。所以執行結果可能是"from future1"、"from future2"、"from future3"中的任意一個。

anyOf 和 acceptEither、applyToEither的區別在于,后兩者只能使用在兩個future中,而anyOf可以使用在多個future中。

3.8 CompletableFuture異常處理

CompletableFuture在運行時如果遇到異常,可以使用get()并拋出異常進行處理,但這并不是一個最好的方法。CompletableFuture本身也提供了幾種方式來處理異常。

3.8.1 exceptionally

方法名描述
exceptionally(Function fn)只有當CompletableFuture拋出異常的時候,才會觸發這個exceptionally的計算,調用function計算值。
        CompletableFuture.supplyAsync(() -> "hello world").thenApply(s -> {s = null;int length = s.length();return length;}).thenAccept(i -> System.out.println(i)).exceptionally(t -> {System.out.println("Unexpected error:" + t);return null;});復制代碼

執行結果:

Unexpected error:java.util.concurrent.CompletionException: java.lang.NullPointerException復制代碼

對上面的代碼稍微做了一下修改,修復了空指針的異常。

        CompletableFuture.supplyAsync(() -> "hello world").thenApply(s -> {
//                    s = null;int length = s.length();return length;}).thenAccept(i -> System.out.println(i)).exceptionally(t -> {System.out.println("Unexpected error:" + t);return null;});復制代碼

執行結果:

11復制代碼

3.8.2 whenComplete

whenComplete 在上一篇文章其實已經介紹過了,在這里跟exceptionally的作用差不多,可以捕獲任意階段的異常。如果沒有異常的話,就執行action。

        CompletableFuture.supplyAsync(() -> "hello world").thenApply(s -> {s = null;int length = s.length();return length;}).thenAccept(i -> System.out.println(i)).whenComplete((result, throwable) -> {if (throwable != null) {System.out.println("Unexpected error:"+throwable);} else {System.out.println(result);}});復制代碼

執行結果:

Unexpected error:java.util.concurrent.CompletionException: java.lang.NullPointerException復制代碼

跟whenComplete相似的方法是handle,handle的用法在上一篇文章中也已經介紹過。

四. CompletableFuture VS Java8 Stream VS RxJava1 & RxJava2

CompletableFuture 有很多特性跟RxJava很像,所以將CompletableFuture、Java 8 Stream和RxJava做一個相互的比較。

composablelazyresuableasynccachedpushback pressure
CompletableFuture支持不支持支持支持支持支持不支持
Stream支持支持不支持不支持不支持不支持不支持
Observable(RxJava1)支持支持支持支持支持支持支持
Observable(RxJava2)支持支持支持支持支持支持不支持
Flowable(RxJava2)支持支持支持支持支持支持支持

五. 總結

Java 8提供了一種函數風格的異步和事件驅動編程模型CompletableFuture,它不會造成堵塞。CompletableFuture背后依靠的是fork/join框架來啟動新的線程實現異步與并發。當然,我們也能通過指定線程池來做這些事情。

CompletableFuture特別是對微服務架構而言,會有很大的作為。舉一個具體的場景,電商的商品頁面可能會涉及到商品詳情服務、商品評論服務、相關商品推薦服務等等。獲取商品的信息時(/productdetails?productid=xxx),需要調用多個服務來處理這一個請求并返回結果。這里可能會涉及到并發編程,我們完全可以使用Java 8的CompletableFuture或者RxJava來實現。

先前的文章:
Java8新的異步編程方式 CompletableFuture(一)
Java8新的異步編程方式 CompletableFuture(二)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287457.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287457.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287457.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

情人節,我表白了CSDN小姐姐后,竟然...【為表白寫了一個繪圖工具,讓我不再手殘】

情人節&#xff0c;我表白了CSDN小姐姐后&#xff0c;竟然…竟然有人看了這篇文。 以下圖片素材由一個還沒寫完的工具繪制&#xff0c;稍后會放在CSDN的代碼倉庫&#xff08;現在能用了&#xff0c;還沒時間改&#xff0c;顏色填充算法還沒寫&#xff0c;有能力的朋友可以修改一…

【小程序】劉一哥課堂隨機點名提問神器V1.0(附源程序)

為了能讓我們的孩子們盡量來教室上課,增強課堂的參與度,激發課堂激情,提高學習效率,一哥也是煞費苦心,于是開發出了這么一款課堂點名提問神器,跟大家分享一下。 打開神器,看到的界面是這樣子的,我很感激有勇氣按時起床并能到教室的每一位有志之士。 點擊【開始】按鈕,…

org.hibernate.HibernateException: No Session found for current thread

spring、springmvc和hibernate整合 在sessionFactory.getCurrentSession()時&#xff0c;出現以下異常 No Session found for current thread但使用sessionFactory.openSession()是沒有任何問題的 嚴重: Servlet.service() for servlet [springDispatcherServlet] in context w…

java mysbatis select_MyBatis SELECT基本查詢實現方法詳解

1、返回一個LISTselect * from tbl_employee where last_name like #{lastName}2、將查詢記錄封裝為一個Mapselect * from tbl_employee where id#{id}返回一條記錄的map&#xff1b;key就是列名&#xff0c;值就是對應的值。3、多條記錄封裝為一個mapMapKey("id")pu…

Git之怎么通過命令修改前面幾次提交的記錄

1 問題 我們平時用gitlab,github發現提交代碼上庫記錄寫錯了&#xff0c;需要修改回來。 2 解決辦法

Git客戶端TortoiseGit(Windows系統)的使用方法

本文環境&#xff1a; 操作系統&#xff1a;Windows XP SP3 Git客戶端&#xff1a;TortoiseGit-1.8.8.0-32bit 一、安裝Git客戶端 全部安裝均采用默認&#xff01; 1. 安裝支撐軟件 msysgit: https://code.google.com/p/msysgit/downloads/list?qfullinstallerofficialgit 當前…

.Net 在容器中操作宿主機

1方案描述 在 docker 容器中想操作宿主機&#xff0c;一般會使用 ssh 的方式&#xff0c;然后 .Net 通過執行遠程 ssh 指令來操作宿主機。本文將使用 交互式 .Net 容器版 中提供的鏡像演示 .Net 在容器中如何操作宿主機。2前期準備 1. 宿主機上生成 ssh key生成 ss…

【看動漫學編程】程序員在異世界生個娃 第1篇:太極村

前言 作者文筆比較水&#xff0c;還請見諒。 以下內容還將使用視頻動態漫畫表現&#xff0c;剪輯完將會貼出鏈接。 小說劇情為劇情需要&#xff0c;過渡到知識點&#xff0c;部分篇幅可能沒有技術知識點還望諒解。 由于沒有經費支持&#xff0c;所以畫出來的東西是我自己用代碼…

【ArcGIS風暴】最牛逼空間數據批處理神器來了:用戶自定義工具箱GeoStorm.tbx

【Warming up】在學習和工作的過程中,作者曾寫過很多采用ArcGIS模型構建器(Model Builder)、Python代碼等批處理方法(感興趣的GISers可以去【測繪地理信息Big風暴專】欄去交流學習指導),大大的減輕了操作壓力,提高了工作效率。今天給大家展示一款神器:自定義工具箱GeoS…

2.6. PostgreSQL表之間連接

到目前為止&#xff0c;我們的查詢一次只訪問了一個表。查詢可以一次訪問多個表&#xff0c;或者用某種方式訪問一個表&#xff0c;而同時處理該表的多個行。一個同時訪問同一個或者不同表的多個行的查詢叫連接查詢。舉例來說&#xff0c;比如你想列出所有天氣記錄以及這些記錄…

Android之Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains

1 問題 用takePhoto去照相的時候特么的一打開就報這個錯誤 2020-04-09 21:33:49.124 19016-19016/com.appsinnova.android.keepshare E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.appsinnova.android.keepshare, PID: 19016java.lang.RuntimeException: Unable to …

Linux下c/c++項目代碼覆蓋率的產生方法

最近做了一系列的單元測試相關的工作&#xff0c;除了各種規范及測試框架以外&#xff0c;討論比較多的就是關于代碼覆蓋率的產生&#xff0c;c/c與其他的一些高級語言或者腳本語言相比較而言&#xff0c;例如 Java、.Net和php/python/perl/shell等&#xff0c;由于沒有這些高級…

C# WPF從后臺代碼生成行列可變的表格

z概述WPF常用的表格控件是DataGrid&#xff0c;這個控件在前臺XAML編寫的話&#xff0c;一般列已經固定&#xff0c;然后給每個列去綁定數據&#xff0c;但是如果我的列不固定&#xff0c;隨著運算結果變動呢&#xff1f;這時候DataGrid&#xff0c;就比較難實現這個需求&#…

軟件架構實踐文章鏈接

2019獨角獸企業重金招聘Python工程師標準>>> 架構 InfoQ: 又拍網架構中的分庫設計 SNS網站數據庫技術分析 - 51CTO.COM 數據庫水平切分的實現原理解析 - iBATIS - Java - JavaEye論壇 基于amoeba的mysql分布式數據庫學習&#xff08;一&#xff09; - Java - JavaEy…

【看動漫學編程】程序員在異世界生個娃 第2篇:外掛已準備就緒

前言 作者文筆比較水&#xff0c;還請見諒。 以下內容還將使用視頻動態漫畫表現&#xff0c;剪輯完將會貼出鏈接。 小說劇情為劇情需要&#xff0c;過渡到知識點&#xff0c;部分篇幅可能沒有技術知識點還望諒解。 由于沒有經費支持&#xff0c;所以畫出來的東西是我自己用代碼…

java剪切txt文件_用Java把剪切板的內容實時保存到txt

test類&#xff1a;提示用戶程序已啟動&#xff0c;提示保存位置&#xff0c;清空剪切板。package com.ariya.service;import com.ariya.service.impl.ClipboardServiceImpl;/*** author Ariya* 程序入口*/public class Test {public static void main(String[] args) {Clipboa…

【三維激光掃描】第一章:三維激光掃描入門基礎知識

隨著地理空間信息服務產業的快速發展,地理空間數據的要求越來越高。對地理空間數據的要求正朝著大信息量、高精度、可視化和可挖掘方向發展。地面激光雷達技術是一門新興的測繪技術,已逐漸成為廣大科研和工程技術人員全新的解決問題的手段。地面三維激光掃描技術與全站儀測量…

Android之kotlin里面本地圖片BitmapFactory.decodeFile轉bitmap失敗問題

1 問題 我們手機本地有個圖片文件比如如下 /storage/emulated/0/Android/data/package_name/cache/1586444511539.png 我們需要png轉bitmap&#xff0c;然后設置到ImageView里面顯示 var bitmap BitmapFactory.decodeFile(imagePath);if (bitmap null) returnelse mImagevi…

3、面向對象-繼承-多態

1、繼承子類可以繼承父類的一切&#xff0c;一個子類只能有一個父類&#xff0c;一個父類可以有多個子類//父類class Ren{public $name;public $sex;public $yuyan;function Say() {echo $this->name."正在講話&#xff01;";}}//美國人的子類class America ex…

整理iOS9適配中出現的坑

一、NSAppTransportSecurity iOS9讓所有的HTTP默認使用了HTTPS&#xff0c;原來的HTTP協議傳輸都改成TLS1.2協議進行傳輸。直接造成的情況就是App發請求的時候彈出網絡無法連接。解決辦法就是在項目的info.plist 文件里加上如下節點&#xff1a; NSAppTransportSecurity - NSAl…