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對象進(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模塊注冊。很多框架型的邏輯,比如統(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; } ); }
如上面的代碼,對于要實(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ù)式寫法,對批量對象操作 */ 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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中dubbo+zookeeper微服務(wù)架構(gòu)簡介
Apache Dubbo是一款高性能的 Java RPC 框架,這篇文章主要介紹了Java中dubbo+zookeeper微服務(wù)架構(gòu),需要的朋友可以參考下2021-09-09springboot?vue測試平臺(tái)接口定義及發(fā)送請求功能實(shí)現(xiàn)
這篇文章主要為大家介紹了springboot+vue測試平臺(tái)接口定義及發(fā)送請求功能實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Java?Selenium實(shí)現(xiàn)修改打開頁面窗口大小
Selenium是一個(gè)強(qiáng)大的自動(dòng)化測試工具,支持多種編程語言和瀏覽器,本文將詳細(xì)介紹如何使用Java?Selenium來修改打開頁面窗口的大小,需要的可以參考下2025-01-01關(guān)于java自定義線程池的原理與實(shí)現(xiàn)
本文介紹了如何自定義線程池和阻塞隊(duì)列,包括阻塞隊(duì)列的實(shí)現(xiàn)方法,線程池的構(gòu)建以及拒絕策略的應(yīng)用,詳細(xì)闡述了線程池中任務(wù)的提交和執(zhí)行流程,以及如何處理任務(wù)超出隊(duì)列容量的情況2022-04-04深入理解 CAS 算法原理已經(jīng)在jdk中的運(yùn)用
這篇文章主要介紹了深入理解 CAS 算法原理已經(jīng)在jdk中的運(yùn)用,幫助大家更好的使用Java,感興趣的朋友可以了解下2020-12-12Java中OkHttp 超時(shí)設(shè)置的實(shí)現(xiàn)
超時(shí)設(shè)置是網(wǎng)絡(luò)編程中不可忽視的一部分,本文就來介紹一下Java中OkHttp 超時(shí)設(shè)置的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06