函式式編程是對行為進行抽象,
編程一生,公眾號:編程一生架構之思-分析那些深入骨髓的設計原則
這句話比較難理解,換句話來說:函式式編程是給自己的物件整容,有可能整的和原來差不多,也有可能整的看起來判若兩人,但是只能處理這個物件,不會對函式外的其他資料產生影響,
函式式編程又結合了lambda運算式和stream API,有些朋友反饋說:函式式編程可讀性不好;還有些朋友反饋說:函式式編程比較難debug,你們說的都對,但是有解決的辦法,看完這篇文章就明白了,
文章整體大綱如下:

lambda運算式
lambda運算式的本質是匿名內部類
先來看一個例子:杜甫的《登高》寫的好,被稱為千古律詩之首,

我從十幾歲的時候開始就一直在想這首詩怎么不押韻:渚清沙白鳥飛回,高中老師講過古語里“回”念huai,這就壓上韻了,但是潦倒新停濁酒杯的杯在古語或者古語方言里念bai嗎?直到如今我還是沒有考證到是否是這樣,我就當它是念bai吧,
這首詩我最喜歡的四句,渲染磅礴的氣勢都含了數字:萬里、百年、無邊、不盡,我突發奇想:讓電腦來給這四句排排序吧,于是我寫了下面的程式:
public void sortDengGao() {
List<String> list = Lists.newArrayList("無邊落木蕭蕭下","不盡長江滾滾來","萬里悲秋常作客","百年多病獨登臺");
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.substring(0, 2).compareTo(o2.substring(0, 2));
}
});
System.out.println(list);
}
我滑鼠點在new Comparator上,提示我匿名內部類可以用lambda代替:

使用Alt+Enter快捷鍵,我回車一下,結果變成了這樣:
public void sortDengGao() {
List<String> list = Lists.newArrayList("無邊落木蕭蕭下","不盡長江滾滾來","萬里悲秋常作客","百年多病獨登臺");
list.sort((o1, o2) -> o1.substring(0, 2).compareTo(o2.substring(0, 2)));
System.out.println(list);
}
當然還可以再執行一次Alt+Enter還原回來,
匿名內部類和lambda運算式既然可以使用快捷鍵相互轉換,那就說明他們本質上是一個東西,這樣就好理解了:在jdk1.8之前,通過匿名內部類訪問區域變數必須要加final關鍵字,jdk1.8之后不需要顯示的加final關鍵字但實際上還是需要被訪問的變數不可變,這就對應了函式式編程不會對函式外的其他資料產生影響,
lambda運算式的省略規則
lambda運算式核心是(對于匿名內部類)采用可推導可省略的原則,所以有些朋友反饋說:函式式編程可讀性不好,因為它做了省略,如果對原本被省略的匿名內部類不熟悉,閱讀就會麻煩些,還有一點哈,撰寫代碼注意換行哈:
list.stream().sorted((o1, o2) -> o1.substring(0, 2).compareTo(o2.substring(0, 2))).close();
這段代碼一個方法用一行是不是好看一些:
list.stream()
.sorted((o1, o2) -> o1.substring(0, 2).compareTo(o2.substring(0, 2)))
.close();
lambda運算式是對匿名內部類的下面三點做了省略:
-
引數型別可省略
-
方法只有一句代碼時:大括號、return和分號可省略
-
方法只有一個引數時小括號可以省略
stream API
stream API就是運用fluent風格的一個特例
對fluent風格不熟悉的強烈建議看看我之前的這篇《代碼榮辱觀-以運用風格為榮,以隨意編碼為恥》,這篇文章邏輯清晰,語言詼諧,比喻恰當,專治不明白,
這里只舉個簡單的例子:StringBuilder一般是這樣使用的:
new StringBuilder().append(1).append(2).toString();
這是典型的fluent風格,咱們來看它包含幾部分:
第一部分:new StringBuffer()構造一個特定物件
第二部分:append()對這個物件本身做處理,可以多次呼叫,每次都回傳它本身
第三部分:toString()結束處理
再來看這個stream API的例子:
list.stream()
.sorted((o1, o2) -> o1.substring(0, 2).compareTo(o2.substring(0, 2)))
.close();
第一部分:.stream()構造一個特定物件
第二部分:sorted()對這個物件本身做處理,可以多次呼叫,每次都回傳它本身
第三部分:close()結束處理
是不是一毛一樣!stream API就是運用fluent風格的一個特例,如此而已,所以我們要關注的點只是.stream()構造的特定物件Stream給我提供了怎么的功能,達到了號稱比sql還簡單、還強大的功能,
一分鐘理解MapReduce
MapReduce現在流行于大資料中的概念,本質上是為了解決對于資料的并行計算方法明明本質上都是采用分治法,但是缺少高層并行編程模型,程式員需要自行指定存盤、計算、分發等任務的問題,MapReduce借鑒了Lisp函式式語言中的思想,用map和reduce兩個函式提供了高層的并發編程模型的抽象,
直白點說就是提供了一個計算手腳架,照著這個架子做開發就可以了,

上面圖中可以看到map的主要功能是把資料分成小塊進行計算,reduce是將小塊計算結果進行合并,在stream API中map和reduce功能也是一樣的,舉個例子:
public void mapReduceDengGao() {
List<String> list = Lists.newArrayList("無邊落木蕭蕭下","不盡長江滾滾來","萬里悲秋常作客","百年多病獨登臺");
String result = list.stream()
.map(word->word+"\n")
.reduce((a,b)->a+""+b)
.get();
System.out.println(result);
}
上面函式先用map方法把list每個元素都進行了處理:后面加換行符,然后用reduce方法對資料合并計算:合并為一個字串,大資料的MapReduce也就是干了這!
用Intellij對stream API做debug
有些朋友反饋說:函式式編程比較難debug,stream trace了解一下,

首先在steam API的地方打上斷點,當運行到斷點處,點擊上面紅色框框里那個圖示,之后會彈出一個框,但是可能一開始沒有資料,提示正在計算,稍等一會之后stream的每一步呼叫結果都可以看到啦:

總結
函式式編程的優勢:
-
代碼可讀性高
-
大資料量下處理集合效率高
-
消滅嵌套地獄
代碼可讀性高,上面已經講過了,因為簡潔明了,
大資料量下處理集合效率高,這個主要是指因為函式式編程功能內聚,JVM優化時去掉了多余的鎖,像上面MapReduce那段講的,采用分治法,使用并行流的話內部做了很好的多執行緒處理,
消滅嵌套地獄嘛,看看下面箭頭形代碼:

用函式式編程效果是這樣的,好看不好看不好說,起碼sonar靜態檢查能過:

推薦閱讀
年紀大了,是否該往管理方向轉型?
演講稿:新人培養之道
最近做code review的5點經驗分享
《躍遷-成為高手的技術》感悟
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/353103.html
標籤:Java
