Java 函數語言程式設計(一)初識篇

微笑面對生活發表於2018-08-15

本文已授權"後端技術精選"獨家釋出。

開發者使用Java8編寫複雜的集合處理演算法,只需要簡單的程式碼就能在多喝cpu上高效執行,這就是Lambda表示式的初衷。

提示:函數語言程式設計和語言無關,它是一種思想,任何語言都可以實現函數語言程式設計,區別只是實現的難易程度不同而已。

在java中,lambda本身就是函數語言程式設計的運用,那什麼是函數語言程式設計呢?

1. 函數語言程式設計是什麼

靠術語解釋是很難理解的,所以,可以通過它的一些特點和優點來感受什麼是函數語言程式設計。重點有做標記。

參考阮一峰文章:www.ruanyifeng.com/blog/2012/0…

1.1 特點

1. 函式是"第一等公民" 所謂"第一等公民"(first class),指的是函式與其他資料型別一樣,處於平等地位,可以賦值給其他變數,也可以作為引數,傳入另一個函式,或者作為別的函式的返回值。 舉例來說,下面程式碼中的print變數就是一個函式,可以作為另一個函式的引數。

var print = function(i){ console.log(i);};

[1,2,3].forEach(print);
複製程式碼

2. 只用"表示式",不用"語句" "表示式"(expression)是一個單純的運算過程,總是有返回值;"語句"(statement)是執行某種操作,沒有返回值。函數語言程式設計要求,只使用表示式,不使用語句。也就是說,每一步都是單純的運算,而且都有返回值。

原因是函數語言程式設計的開發動機,一開始就是為了處理運算(computation),不考慮系統的讀寫(I/O)。"語句"屬於對系統的讀寫操作,所以就被排斥在外。

當然,實際應用中,不做I/O是不可能的。因此,程式設計過程中,函數語言程式設計只要求把I/O限制到最小,不要有不必要的讀寫行為,保持計算過程的單純性。

3. 沒有"副作用"

所謂"副作用"(side effect),指的是函式內部與外部互動(最典型的情況,就是修改全域性變數的值),產生運算以外的其他結果。

函數語言程式設計強調沒有"副作用",意味著函式要保持獨立,所有功能就是返回一個新的值,沒有其他行為,尤其是不得修改外部變數的值.

4 . 不修改狀態

上一點已經提到,函數語言程式設計只是返回新的值,不修改系統變數。因此,不修改變數,也是它的一個重要特點。

在其他型別的語言中,變數往往用來儲存"狀態"(state)。不修改變數,意味著狀態不能儲存在變數中。函數語言程式設計使用引數儲存狀態,最好的例子就是遞迴。

5. 引用透明

引用透明(Referential transparency),指的是函式的執行不依賴於外部變數或"狀態",只依賴於輸入的引數,任何時候只要引數相同,引用函式所得到的返回值總是相同的。

有了前面的第三點和第四點,這點是很顯然的。其他型別的語言,函式的返回值往往與系統狀態有關,不同的狀態之下,返回值是不一樣的。這就叫"引用不透明",很不利於觀察和理解程式的行為。

1.2 優點

1. 程式碼簡潔,開發快速 2. 接近自然語言,易於理解

(1+2)*3-4用函式式語言表達

add(1,2).multiply(3).subtract(4)
複製程式碼

3. 更方便的程式碼管理

不依賴、也不會改變外界的狀態,只要給定輸入引數,返回的結果必定相同。因此,每一個函式都可以被看做獨立單元,很有利於進行單元測試(unit testing)和除錯(debugging),以及模組化組合。

4. 易於"併發程式設計"

函數語言程式設計不需要考慮"死鎖"(deadlock),因為它不修改變數,所以根本不存在"鎖"執行緒的問題。不必擔心一個執行緒的資料,被另一個執行緒修改,所以可以很放心地把工作分攤到多個執行緒,部署"併發程式設計"(concurrency)。

2. 函數語言程式設計例項

函數語言程式設計關心資料的對映,指令式程式設計關心解決問題的步驟。

函式式風格沒有賦值,也就沒有for迴圈, 要實現迴圈操作 只能通過遞迴呼叫。

public class First {
    public static void main(String[] args) {
        int a = 10,b = 20;
        int c = a+b;
        System.out.println(c);
    }
}
複製程式碼

這段程式碼是用命令來表示程式,用命令的執行順序來表示程式的組合,所以不是函數語言程式設計。差不多是程式導向的思想。

public class First {
    public static void main(String[] args) {
        int a = 10,b = 20;
        add(a,b);
    }
    static int add(int a,int b){
        int c = a+b;
        return c;
    }
}
複製程式碼

這段程式碼用函式來表示程式,但是內部是用命令的組合來實現,不算真正意義上的函數語言程式設計。物件導向的思想。

public class First {
    public static void main(String[] args) {
        int a = 10,b = 20;
        add(a,b);
    }
    static int add(int a,int b){
        return a+b;
    }
}
複製程式碼

這段程式碼用函式來表示程式,用函式的組合來表達程式的組合,是完全的函數語言程式設計。

物件導向、程式導向和函數語言程式設計區別

“程式導向”和“物件導向”的區別是“封裝”。“函式式”和“物件導向”的區別是“不使用外部狀態”。上面的三段程式碼中也有體現。

如有異議,請在下方評論,謝謝。

相關文章