Java8函數(shù)式編程應用小結(jié)
我們經(jīng)常提到,Java8是革命性的一個版本,原因就是正式引入了函數(shù)式編程,那Java的函數(shù)式編程在實際應用中到底有什么用呢?結(jié)合實際的應用,我整理出了函數(shù)式在Java的幾個經(jīng)典用途。
緩求值
惰性求值(Lazy evaluation)是在需要時才進行求值的計算方式。惰性求值自然地在數(shù)據(jù)結(jié)構(gòu)中包含遞歸,可以以簡單的方式表示無限的概念,這種方式有利于程序的模塊化。
在Java這種Strict語言中,我們定義了臨時變量代碼塊就會立即運算并且取得結(jié)果,而實際上很多結(jié)果未必會使用到,就存在不必要的計算,如下面的代碼
/**
* 是否是標準或默認工作臺
* 理論上僅判斷默認工作臺即可(因為標準就是默認),此處是兜底一下歷史邏輯
*
* @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();
}當我們使用臨時變量定義的時候,需要理解計算出代碼
StringUtils.isNotBlank(context.getDefaultAppUuid())
&& StringUtils.equals(context.getAppUuid(), context.getDefaultAppUuid())的值,并用于后面的判斷,不管下面的代碼是否為True,我們都消耗了一次計算
WorkbenchType.WORKBENCH.equals(context.getWorkbenchType())
而我們使用了Supplier,就可以定義一個匿名表達式,只有當前面判斷為False的時候,才會執(zhí)行
isDefaultWorkbench.get()
,而當前面判斷為True的時候,就不會執(zhí)行后面的代碼了,通過緩求值的方式,可以節(jié)省在某些情況下的消耗,可以提升系統(tǒng)性能,節(jié)省資源。
高階函數(shù)
高階函數(shù)是指使用其他函數(shù)作為參數(shù)、或者返回一個函數(shù)作為結(jié)果的函數(shù)。
我們常用的Stream就是典型的流處理思想,可以通過Stream來處理集合并執(zhí)行相關(guān)的操作,其中Stream包含了大量的高階函數(shù),我們可以直接使用匿名表達式來傳遞業(yè)務(wù)邏輯。值得注意,匿名表達式本身返回的就是函數(shù),因此匿名表達式就是一種高階函數(shù)。
// 過濾隱藏應用
return appDetails.stream().filter(app -> {
AppModel appModel = new AppModel(app.getAppId(), app.getAppType());
return !appDisplayModel.getHideApps().contains(appModel);
}).collect(Collectors.toList());從上面可以邏輯可以看到,我們可以通過集合的Stream對象進行filter、map、collect操作,其中這些高階函數(shù)就可以傳遞lambda表達式,用于處理我們需要的邏輯。
當然除了Stream之外,Java很多工具類也支持外部傳入lambda,比如還有一種常見的工具類Optional。
/**
* 獲取組織默認工作臺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表達式。
函數(shù)回調(diào)
在計算機程序設(shè)計中,回調(diào)函數(shù),或簡稱回調(diào)(Callback 即call then back 被主函數(shù)調(diào)用運算后會返回主函數(shù)),是指通過參數(shù)將函數(shù)傳遞到其它代碼的,某一塊可執(zhí)行代碼的引用。 這一設(shè)計允許了底層代碼調(diào)用在高層定義的子程序。
函數(shù)回調(diào)可用于接口兩塊完全無關(guān)的邏輯,比如在A模塊執(zhí)行完畢后,執(zhí)行B模塊,B模塊的代碼事先在A模塊注冊。很多框架型的邏輯,比如統(tǒng)一結(jié)果處理、緩存框架、分布式鎖、線程緩存等都可以通過這個方式來優(yōu)化,就可以使用lambda的方式來實現(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;
}
);
}如上面的代碼,對于要實現(xiàn)分布式鎖控制的模塊,可以使用lambda的回調(diào),來實現(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ū)ο竺钍骄幊痰膹碗s度。即盡量把處理邏輯都抽象成可復用的函數(shù),并通過lambda的方式進行調(diào)用。
/**
* 批量操作
*
* @param consumer 函數(shù)式寫法,對批量對象操作
*/
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));
}如上圖所示,就是在類中定義了一個高階函數(shù),在調(diào)用的時候從外部傳入lambda表達式,從而實現(xiàn)batchProccess和pushFacadeService.push兩個方法的解耦。上面的核心和集合支持lambda是一個意思,也就是把需要外部頻繁操作的部分抽象出來定義成函數(shù)式接口,以供外部傳入不同的lambda進行豐富的操作。
總結(jié)
Java8非常重要的就是引入了函數(shù)式編程的思想,使得這門經(jīng)典的面向?qū)ο笳Z言有了函數(shù)式的編程方式。彌補了很大程度上的不足,函數(shù)式思想在處理復雜問題上有著更為令人稱贊的特性。
到此這篇關(guān)于Java8函數(shù)式編程應用小結(jié)的文章就介紹到這了,更多相關(guān)Java8函數(shù)式編程應用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中dubbo+zookeeper微服務(wù)架構(gòu)簡介
Apache Dubbo是一款高性能的 Java RPC 框架,這篇文章主要介紹了Java中dubbo+zookeeper微服務(wù)架構(gòu),需要的朋友可以參考下2021-09-09
springboot?vue測試平臺接口定義及發(fā)送請求功能實現(xiàn)
這篇文章主要為大家介紹了springboot+vue測試平臺接口定義及發(fā)送請求功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05
Java?Selenium實現(xiàn)修改打開頁面窗口大小
Selenium是一個強大的自動化測試工具,支持多種編程語言和瀏覽器,本文將詳細介紹如何使用Java?Selenium來修改打開頁面窗口的大小,需要的可以參考下2025-01-01
關(guān)于java自定義線程池的原理與實現(xiàn)
本文介紹了如何自定義線程池和阻塞隊列,包括阻塞隊列的實現(xiàn)方法,線程池的構(gòu)建以及拒絕策略的應用,詳細闡述了線程池中任務(wù)的提交和執(zhí)行流程,以及如何處理任務(wù)超出隊列容量的情況2022-04-04
Java中OkHttp 超時設(shè)置的實現(xiàn)
超時設(shè)置是網(wǎng)絡(luò)編程中不可忽視的一部分,本文就來介紹一下Java中OkHttp 超時設(shè)置的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-06-06

