摘要:函數式編程概述如今主流的編程語言,函數式編程范式或多或少都融入其中成了標配,或者說主流語言都在進行函數式方面的擴充,這是一個大趨勢。
函數式編程概述
如今主流的編程語言,函數式編程范式或多或少都融入其中成了“標配”,或者說主流語言都在進行函數式方面的擴充,這是一個大趨勢。以Java為例,隨著 Lambda塊 和 Stream API 等這種高階函數的加持,Java總算是裝備了函數式這一利器;博大精深的C++也在2011版的語言標準里加入了Lambda塊的支持;再比如前一段時間我初步體驗了的 Groovy語言,雖然其運行于JVM之上,然而其對 動態語言、函數式編程范式 以及 元編程功能 的加持所帶來的表現力和簡潔性可以說甩了Java幾條街,可以利用Groovy的所有動態功能構建高性能的JVM應用、將開發效率提高幾個數量級。語言的例子有很多,我不一一枚舉。
注: 本文首發于 My 公眾號 CodeSheep ,可 長按 或 掃描 下面的 小心心 來訂閱 ↓ ↓ ↓為什么要使用函數式編程范式
這里講幾個函數式編程的典型特點,區別的對象那就是傳統的命令式編程
0x01. 更高層次的抽象(高階函數)
用高階抽象來取代基本的控制結構本身就是一個全新的思考方式,這樣可以讓開發者聚焦精力于業務場景而無需費心復雜地層運作
舉個栗子:將一個字符串集合中的所有單詞轉為大寫,我們用Java語言來實現
如果按照傳統的命令式編程的解法,那接下來不出意外我們得來寫循環、遍歷這種迭代操作了:
for (int i=0; i但如果使用Java的函數式編程范式,一切都是那么的優雅,一句話搞定
wordList.stream.map( w -> w.toUpperCase() )這里的map()函數就是所謂的高階函數,我們用高階函數代替了底層的迭代,因為我們并沒有處理細節,我們僅僅定義了映射的邏輯,迭代由高階函數來自動完成!
0x02. 提升代碼信噪比(簡潔性)
區別于面向對象語言用抽象來封裝不確定因素,函數式編程通過盡量減少不確定因素來使代碼極度簡潔上面的例子對于本條優點的展現我想應該也不必多說了
0x03. 控制權轉交于運行時(動態性)
區別于傳統的編譯形語言,配備函數式編程范式的動態語言更多的將控制權轉交到語言運行時手里,獲得的則是更高的靈活性、表現力和性能權衡。這三點優點將在接下來的例子中切實的感受并領會!
函數式編程例析 舉例1:詞頻統計做的事情很簡單:給定一個單詞集合,統計出集合中除了助詞(如of、on、the等)之外的單詞出現的頻次,不區分大小寫
命令式解法: 至少分為以下幾大步
先進行循環迭代
然后統一將單詞轉為小寫
然后判斷單詞是否是助詞
最后進行詞頻統計
public class WordCount { // 定義一個助詞集合,這些單詞不參與計數 private SetauxiliaryWordSet = new HashSet () {{ add("of"); add("the"); add("to"); add("and"); add("so"); add("are"); }}; // 傳統命令式解法實現的詞頻統計函數 public Map doWordCount( List context ) { Map result = new HashMap (); for ( String word:context ) { // 循環迭代 String lowerCaseWord = word.toLowerCase(); // 將單詞統一轉換為小寫 if( !auxiliaryWordSet.contains(lowerCaseWord) ) { if( null == result.get(lowerCaseWord) ) result.put( lowerCaseWord, 1 ); else result.put( lowerCaseWord, result.get(lowerCaseWord)+1 ); } } return result; } // main() 函數 public static void main(String[] args) { List wordList = new ArrayList () {{ add("The"); add("Products"); add("of"); add("Samsung"); add("and"); add("Apple"); add("are"); add("so"); add("amazing"); add("especially"); add("Apple"); }}; WordCount wordCount = new WordCount(); Map res = wordCount.doWordCount( wordList ); System.out.print(res); // 打印:{apple=2, amazing=1, samsung=1, especially=1, products=1} } } 函數式解法:
如果我們用Java的Stream API和Lambda塊所構成的函數式范式來重寫 doWordCount() 函數,一切都將如此簡潔:
public Map doWordCount2( Listcontext ) { Map result = new HashMap (); context.stream().map( w -> w.toLowerCase() ) .filter( w -> !auxiliaryWordSet.contains(w) ) .forEach( w -> result.put( w, result.getOrDefault(w,0) + 1 ) ); return result; } 備注:這里的getOrDefault是Java的Map提供的一個便利函數,意思是:在Map中若沒有找到給定的key時,返回一個“默認值”對比命令式解法,用戶省去了很多繁瑣的迭代和判斷,我們只講焦點聚焦在業務邏輯之上,代碼信噪比提升不小吧!
舉例2:連詞成句給定一個離散的單詞集合,我們想將字母數大于1的單詞的首字母大寫后,用 短橫線- 連接起來成為一個句子
命令式解法:
public class WordConnect { // 將單詞的首字母大寫 public String capitalizeFirstLetter( String s ) { return s.substring(0,1).toUpperCase() + s.substring(1,s.length() ); } // 連詞成句 public String connectWord( Listcontext ) { StringBuilder result = new StringBuilder(); for ( String word: context ) { if ( word.length() > 1 ) { result.append( capitalizeFirstLetter(word) ); result.append("-"); } } return result.substring(0,result.length()-1).toString(); } // main()函數 public static void main(String[] args) { List wordList = new ArrayList () {{ add("The"); add("Products"); add("of"); add("Samsung"); add("and"); add("Apple"); add("are"); add("so"); add("amazing"); add("especially"); add("Apple"); }}; WordConnect wordConnect = new WordConnect(); String res = wordConnect.connectWord( wordList ); System.out.print(res); // 打印:The-Products-Of-Samsung-And-Apple-Are-So-Amazing-Especially-Apple } } 函數式解法1: Java Steam API 和 Lambda塊實現
public String connectWord( Listcontext ) { return context.stream().filter( w -> w.length()>1 ) .map( w -> capitalizeFirstLetter(w) ) .collect( Collectors.joining("-") ); } 我什么都不想說了,這不要太簡潔好吧!
函數式解法2: Groovy語言實現
public String connectWord( context ) { context.findAll { it.length() >1 } .collect { it.capitalize() } .join "-" }關于Groovy語言的初體驗,可以參考我的文章:Groovy初體驗:構建高性能JVM應用
函數式最佳實踐:高效編寫三行情書還記得去年的520,為了表達心中對于老婆無限的、無法表達的愛,我想寫一封不超過三行的代碼情書,我更想用盡可能短的代碼來盡可能多地表達,于是我選擇了函數式編程。
我的520三行代碼情書在此:
public TimeRiver timeFlow( List后記days ) { return (TimeRiver)days.stream() .filter( n->theDaysNotWithYou(n) ) .map( e->accompanyByMyLove(e) ) .collect( Collectors.joining("??") ); } 文中提到的Groovy動態編程語言,作者體驗過一點,可以參考:Groovy初體驗:構建高性能JVM應用
如果有興趣,也來看看作者一些關于容器化、微服務化方面的文章:
RPC框架實踐之:Apache Thrift
微服務調用鏈追蹤中心搭建
利用K8S技術棧打造個人私有云連載文章
Docker容器可視化監控中心搭建
利用ELK搭建Docker容器化應用日志中心
Spring Boot應用監控實戰
作者更多的原創文章:在此
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69588.html
摘要:由于技術棧的學習,筆者需要在原來函數式編程知識的基礎上,學習的使用。筆者在社區發現了一個非常高質量的響應式編程系列教程共篇,從基礎概念到實際應用講解的非常詳細,有大量直觀的大理石圖來輔助理解流的處理,對培養響應式編程的思維方式有很大幫助。 showImg(https://segmentfault.com/img/bVus8n); [TOC] 一. 響應式編程 響應式編程,也稱為流式編程...
摘要:項目進展通過神荼科技全面安全審計經過一個多月的全面審計工作,神荼科技于本周交付相關安全審計測試報告,給出初步整改建議。剩余問題也已反饋到研發部門,將在近期得到解決并進一步與神荼科技溝通,進行二次審計。 showImg(https://segmentfault.com/img/bVbtKHf); 項目進展 Highlight:ETM 通過神荼科技全面安全審計 經過一個多月的全面審計工作,...
摘要:本文是響應式編程第一章響應式這篇文章的學習筆記。通過代碼對比可以發現,在響應式編程中,我們不再用對象的概念來對現實世界進行建模,而是使用流的思想對信息進行拆分和聚合。 本文是Rxjs 響應式編程-第一章:響應式這篇文章的學習筆記。示例代碼地址:【示例代碼】 更多文章:【《大史住在大前端》博文集目錄】 showImg(https://segmentfault.com/img/bVbuE...
閱讀 1427·2021-09-22 15:52
閱讀 1470·2019-08-30 15:44
閱讀 902·2019-08-30 14:24
閱讀 2713·2019-08-30 13:06
閱讀 2706·2019-08-26 13:45
閱讀 2788·2019-08-26 13:43
閱讀 1026·2019-08-26 12:01
閱讀 1446·2019-08-26 11:56