摘要:一提到編程範式,很容易聯想到宗教的虔誠,每種宗教所表達信條都有必定合理性,但若是一直只遵循一種教條,可能也被讓本身痛苦不堪,編程範式也是如此。
案例一,代碼摘抄來自一企業培訓材料,主要代碼邏輯是打印每課成績,並找出學生非F級別課程統計平均分數:算法
class CourseGrade { public String title; public char grade; } public class ReportCard { public String studentName; public ArrayList<CourseGrade> cliens; public void printReport() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); System.out.println("Course Title Grade"); Iterator<CourseGrade> grades = cliens.iterator(); CourseGrade grade; double avg = 0.0d; while (grades.hasNext()) { grade = grades.next(); System.out.println(grade.title + " " + grade.grade); if (!(grade.grade == 'F')) { avg = avg + grade.grade - 64; } } avg = avg / cliens.size(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + avg); } }
上面的代碼有哪些問題呢:編程
培訓材料並未給標準解題,嘗試優化一下代碼,採用Java8的Stream來簡化計算過程,並對代碼進行了分段:segmentfault
public void printReport2() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); System.out.println("Course Title Grade"); cliens.forEach(it -> System.out.println(it.title + " " + it.grade)); double total = cliens.stream().filter(it -> it.grade != 'F') .mapToDouble(it -> it.grade - 64).sum(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + total / cliens.size()); }
進一步優化,把各種打印抽取各自函數:設計模式
private void printHeader() { System.out.println("Report card for " + studentName); System.out.println("------------------------"); } private void printGrade() { System.out.println("Course Title Grade"); cliens.forEach(it -> System.out.println(it.title + " " + it.grade)); } private void printAverage() { double total = cliens.stream().filter(it -> it.grade != 'F') .mapToDouble(it -> it.grade - 64).sum(); System.out.println("------------------------"); System.out.println("Grade Point Average = " + total / cliens.size()); } public void printReport3() { printHeader(); printGrade(); printAverage(); }
注:若是隻算非F的平均分,能夠一行搞定:閉包
double avg = cliens.stream().filter(it -> it.grade != 'F').mapToDouble(it -> it.grade - 64).average().orElse(0.0d);
List<Integer> tanscationsIds = transcations.parallelStream() .filter(it -> it.getType() == Transcation.GROCERY) .sorted(comparing(Transcation::getValue).resersed()) .map(Transcation::getId) .collect(Collectors::toList());
代碼很是清晰:編程語言
這看起來是否是像這樣一條SQL語句:select t.id from tanscations t where t.type == 'GROCERY' order by t.value desc函數式編程
目前Java8已普遍使用,對於Stream與Lambda應習覺得常了,而再也不是一種炫技。網上也有很是多的教程,如有同窗還不熟悉他們的用法,能夠多找找材料熟悉一下。函數
Stream正如其名,像一條數據生產流水線,逐步疊加中間操做(算法和計算),把數據源轉換爲另外一個數據集。工具
筆者很早之前學過C#,接觸過LINQ(Language Integrated Query),它比Java的Stream和Lambda用法更爲清晰簡潔,先給個簡單示例:學習
var result = db.ProScheme.OrderByDescending(p => p.rpId).Where(p => p.rpId > 10).ToList();
LINQ爲數據查詢而生,能夠算是DSL(Domain Specific Language)了,背後也是函數式編程(FP)一套理念,先記住其中兩點:
FP還有其它的特性:模式匹配,柯里化,偏函數,閉包,尾遞歸等。對FP感受興趣的同窗不妨找找材料學習一下。
如今的主流語言,都引入一些FP特性來提高語言在數據上的表達能力。
C++11引入Lambda表達式,並提供<algorithm>,<functional>兩個基礎庫,一個簡單示例:
int foo[] = { 10, 20, 5, 15, 25 }; std::sort(foo, foo+5, [](int a,int b){return a > b;});
Python提供functools庫來簡化一些函數式編程(仍是至關的弱),一個簡單示例:
foo = ["A", "a", "b", "B"] sorted(foo, key=functools.cmp_to_key(locale.strcoll))
固然,面嚮對象語言中增長lambda這類特徵不能就稱爲函數式編程了,大部分只不過是語法糖。是採用什麼編程範式不在於語言的語法,而是在於思惟方式。
面向對象編程(OOP)在過去20多年很是成功,而函數式編程(FP)也不斷地發展,他們相生相息,各自解決不一樣的場景問題:
現實業務需求每每體現爲業務活動,它是面向過程的,即先輸入數據源,在必定條件下,進行一系列的交互,再輸出結果。那面向過程與函數式的的區別是什麼:
面向對象的編程經過封裝可變的部分來構造可以讓人讀懂的代碼,函數式編程則是經過最大程度地減小可變的部分來構造出可以讓人讀懂的代碼。
咱們從Java的Stream實現也看到函數式的另外一個特色:
結合上面的理解,咱們能夠先把世界事物經過OOP抽象爲對象,再把事物間的聯繫與交互經過FP抽象爲執行單元,這種結合或許是對業務活動的實現一種較好的解決方式。
一提到編程範式,很容易聯想到宗教的虔誠,每種宗教所表達信條都有必定合理性,但若是一直只遵循一種教條,可能也被讓本身痛苦不堪。編程範式也是如此,正如Java在1.8以前是純面向對象式,你就會以爲它很是繁瑣。也如Erlang是純函數式,你就會發現有時簡單的邏輯處理會很是複雜。
近些年來,因爲數據分析、科學計算和並行計算的興起,讓人認識到函數式編程解決數據領域的魅力,它也愈來愈受歡迎。在這些領域,程序每每比較容易用數據表達式來表達,採用函數式能夠用不多代碼來實現。
現實的業務軟件,不少的邏輯其實也是對數據的處理,最簡單是對數據的CURD,以及數據的組合、過濾與查詢。因此函數式編程在許多語言中都獲得支持,提高了對數據處理的表達能力。
瞭解新的編程範式在適當的時候使用它們,這會使你事半功倍。不管什麼編程範式,他們都是工具,在你的工具箱中,可能有錘子,螺絲刀…,這個工具在何時使用,取決待解決的問題。
本文的案例只是一個引子,主要是想給你帶來函數式編程的一些理念,函數式給咱們解決業務問題提供了另外一種思惟方式:如何高效簡潔地對數據查詢與變換。許多語言都支持函數式一些能力,須要咱們不斷地學習,在合理的場景下使用他們。
本文分享自華爲雲社區《飛哥講代碼16:函數式讓數據處理更簡潔》,原文做者:華爲雲專家。