Java8函數(shù)式編程應(yīng)用小結(jié)
我們經(jīng)常提到,Java8是革命性的一個(gè)版本,原因就是正式引入了函數(shù)式編程,那Java的函數(shù)式編程在實(shí)際應(yīng)用中到底有什么用呢?結(jié)合實(shí)際的應(yīng)用,我整理出了函數(shù)式在Java的幾個(gè)經(jīng)典用途。
緩求值
惰性求值(Lazy evaluation)是在需要時(shí)才進(jìn)行求值的計(jì)算方式。惰性求值自然地在數(shù)據(jù)結(jié)構(gòu)中包含遞歸,可以以簡單的方式表示無限的概念,這種方式有利于程序的模塊化。
在Java這種Strict語言中,我們定義了臨時(shí)變量代碼塊就會(huì)立即運(yùn)算并且取得結(jié)果,而實(shí)際上很多結(jié)果未必會(huì)使用到,就存在不必要的計(jì)算,如下面的代碼
/**
* 是否是標(biāo)準(zhǔn)或默認(rèn)工作臺(tái)
* 理論上僅判斷默認(rèn)工作臺(tái)即可(因?yàn)闃?biāo)準(zhǔn)就是默認(rèn)),此處是兜底一下歷史邏輯
*
* @param context
* @return
*/
public boolean isStandardOrDefaultWorkbench(SchemaContext context) {
Supplier<Boolean> isDefaultWorkbench = () -> StringUtils.isNotBlank(context.getDefaultAppUuid())
&& StringUtils.equals(context.getAppUuid(), context.getDefaultAppUuid());
return WorkbenchType.WORKBENCH.equals(context.getWorkbenchType()) || isDefaultWorkbench.get();
}當(dāng)我們使用臨時(shí)變量定義的時(shí)候,需要理解計(jì)算出代碼
StringUtils.isNotBlank(context.getDefaultAppUuid())
&& StringUtils.equals(context.getAppUuid(), context.getDefaultAppUuid())的值,并用于后面的判斷,不管下面的代碼是否為True,我們都消耗了一次計(jì)算
WorkbenchType.WORKBENCH.equals(context.getWorkbenchType())
而我們使用了Supplier,就可以定義一個(gè)匿名表達(dá)式,只有當(dāng)前面判斷為False的時(shí)候,才會(huì)執(zhí)行
isDefaultWorkbench.get()
,而當(dāng)前面判斷為True的時(shí)候,就不會(huì)執(zhí)行后面的代碼了,通過緩求值的方式,可以節(jié)省在某些情況下的消耗,可以提升系統(tǒng)性能,節(jié)省資源。
高階函數(shù)
高階函數(shù)是指使用其他函數(shù)作為參數(shù)、或者返回一個(gè)函數(shù)作為結(jié)果的函數(shù)。
我們常用的Stream就是典型的流處理思想,可以通過Stream來處理集合并執(zhí)行相關(guān)的操作,其中Stream包含了大量的高階函數(shù),我們可以直接使用匿名表達(dá)式來傳遞業(yè)務(wù)邏輯。值得注意,匿名表達(dá)式本身返回的就是函數(shù),因此匿名表達(dá)式就是一種高階函數(shù)。
// 過濾隱藏應(yīng)用
return appDetails.stream().filter(app -> {
AppModel appModel = new AppModel(app.getAppId(), app.getAppType());
return !appDisplayModel.getHideApps().contains(appModel);
}).collect(Collectors.toList());從上面可以邏輯可以看到,我們可以通過集合的Stream對(duì)象進(jìn)行filter、map、collect操作,其中這些高階函數(shù)就可以傳遞lambda表達(dá)式,用于處理我們需要的邏輯。
當(dāng)然除了Stream之外,Java很多工具類也支持外部傳入lambda,比如還有一種常見的工具類Optional。
/**
* 獲取組織默認(rèn)工作臺(tái)appUuid
* @param corpId
* @param orgConfigTag
* @return
*/
public String getDefaultWorkbenchAppUuid(String corpId, OrgConfigTag orgConfigTag) {
return Optional.ofNullable(orgConfigTag).map(OrgConfigTag::getDefaultAppUuid)
.orElseGet(() -> OpenPageUtils.buildWorkbenchAppUuid(corpId));
}其中的orElseGet方法就支持外部傳入lambda表達(dá)式。
函數(shù)回調(diào)
在計(jì)算機(jī)程序設(shè)計(jì)中,回調(diào)函數(shù),或簡稱回調(diào)(Callback 即call then back 被主函數(shù)調(diào)用運(yùn)算后會(huì)返回主函數(shù)),是指通過參數(shù)將函數(shù)傳遞到其它代碼的,某一塊可執(zhí)行代碼的引用。 這一設(shè)計(jì)允許了底層代碼調(diào)用在高層定義的子程序。
函數(shù)回調(diào)可用于接口兩塊完全無關(guān)的邏輯,比如在A模塊執(zhí)行完畢后,執(zhí)行B模塊,B模塊的代碼事先在A模塊注冊(cè)。很多框架型的邏輯,比如統(tǒng)一結(jié)果處理、緩存框架、分布式鎖、線程緩存等都可以通過這個(gè)方式來優(yōu)化,就可以使用lambda的方式來實(shí)現(xiàn)。核心的邏輯就是先處理相關(guān)的通用的中間件邏輯,然后通過lambda來執(zhí)行業(yè)務(wù)邏輯。
/**
* 創(chuàng)建我的頁面
*
* @param corpId
* @param uid
*/
protected void createMyPage(String corpId, Long uid, String appUuid, Method method) throws WorkbenchException {
// 并發(fā)鎖控制
distributeLockSupport.lockAndDo(key,
() -> {
//創(chuàng)建頁面方法
userCorpPageSupport.createMyPage(corpId, uid);
return null;
}
);
}如上面的代碼,對(duì)于要實(shí)現(xiàn)分布式鎖控制的模塊,可以使用lambda的回調(diào),來實(shí)現(xiàn)加鎖和業(yè)務(wù)邏輯的分離。其中的定義如下述代碼所示
/**
* 基于緩存的分布式鎖操作
*
* @param key 資源key
* @param callback 回調(diào)函數(shù)
* @param <T> 返回結(jié)果類型
* @return
* @throws Exception
*/
public <T> T lockAndDo(String key, Callback<T> callback) throws WorkbenchException {
//取鎖
...
try {
//加鎖
...
return callback.process();
} catch (WorkbenchException ex) {
throw ex;
} finally {
try {
//釋放鎖
...
} catch (Exception ex) {
//異常處理
}
}
}
//回調(diào)接口定義,供外部傳入lambda
@FunctionalInterface
public interface Callback<T> {
/**
* 回調(diào)處理
*
* @return 處理結(jié)果
* @throws WorkbenchException
*/
T process() throws WorkbenchException, ServiceException;
}自定義函數(shù)
從函數(shù)式編程的核心思想來說,函數(shù)是一等公民,而面向?qū)ο蟮暮诵氖欠庋b??梢酝ㄟ^定義函數(shù)的方式來降低面向?qū)ο竺钍骄幊痰膹?fù)雜度。即盡量把處理邏輯都抽象成可復(fù)用的函數(shù),并通過lambda的方式進(jìn)行調(diào)用。
/**
* 批量操作
*
* @param consumer 函數(shù)式寫法,對(duì)批量對(duì)象操作
*/
public void batchProccess(BiConsumer<Long, OrchardDTO> consumer) {
if(orchardDTOMap!=null && orchardDTOMap.size()>0){
for (Map.Entry<Long, OrchardDTO> entry : orchardDTOMap.entrySet()) {
consumer.accept(entry.getKey(), entry.getValue());
}
}
}public void syncPush(MicroAppContext context, BatchOrchardDTO batchOrchardDTO) {
//傳入lambda來執(zhí)行邏輯
batchOrchardDTO.batchProccess((k, v) -> pushFacadeService.push(k, v));
}如上圖所示,就是在類中定義了一個(gè)高階函數(shù),在調(diào)用的時(shí)候從外部傳入lambda表達(dá)式,從而實(shí)現(xiàn)batchProccess和pushFacadeService.push兩個(gè)方法的解耦。上面的核心和集合支持lambda是一個(gè)意思,也就是把需要外部頻繁操作的部分抽象出來定義成函數(shù)式接口,以供外部傳入不同的lambda進(jìn)行豐富的操作。
總結(jié)
Java8非常重要的就是引入了函數(shù)式編程的思想,使得這門經(jīng)典的面向?qū)ο笳Z言有了函數(shù)式的編程方式。彌補(bǔ)了很大程度上的不足,函數(shù)式思想在處理復(fù)雜問題上有著更為令人稱贊的特性。
到此這篇關(guān)于Java8函數(shù)式編程應(yīng)用小結(jié)的文章就介紹到這了,更多相關(guān)Java8函數(shù)式編程應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud中的斷路器(Hystrix)和斷路器監(jiān)控(Dashboard)
本篇主要介紹的是SpringCloud中的斷路器(Hystrix)和斷路器指標(biāo)看板(Dashboard)的相關(guān)使用知識(shí),需要的朋友可以參考下2019-06-06
java?kafka如何動(dòng)態(tài)設(shè)置用戶讀寫權(quán)限
這篇文章主要介紹了java?kafka如何動(dòng)態(tài)設(shè)置用戶讀寫權(quán)限問題,具有很好的參考家價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
WebSocket(java版)服務(wù)核心實(shí)例代碼
WebSocket是一種協(xié)議,用于在Web應(yīng)用程序和服務(wù)器之間建立實(shí)時(shí)、雙向的通信連接,這篇文章主要介紹了WebSocket(java版)服務(wù)核心代碼的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-12-12
Java動(dòng)態(tài)導(dǎo)出Word登記表的完整方案
本文詳細(xì)講解如何使用 Java動(dòng)態(tài)導(dǎo)出包含多人員報(bào)名表的Word文檔,每人占據(jù)獨(dú)立一頁,并支持動(dòng)態(tài)表格行,我們對(duì)比了多種實(shí)現(xiàn)方案,最終推薦基于 Freemarker + XML模板或docx4j的靈活方式,并提供完整代碼示例與最佳實(shí)踐,助你高效實(shí)現(xiàn)復(fù)雜Word導(dǎo)出需求2025-07-07
windows下zookeeper配置java環(huán)境變量的方法
今天小編就為大家分享一篇關(guān)于windows下zookeeper配置java環(huán)境變量的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
springboot + devtools(熱部署)實(shí)例教程
devtools是boot的一個(gè)熱部署工具,當(dāng)我們修改了classpath下的文件(包括類文件、屬性文件、頁面等)時(shí),會(huì)重新啟動(dòng)應(yīng)用。本文通過實(shí)例給大家介紹springboot+devtools熱部署,感興趣的朋友一起看看吧2017-04-04

