來自:碼農翻身(微訊號:coderising)
1
小函式的運氣不好,投胎到了邪惡的Java帝國,一齣生就被告知了自己的悲慘地位,以及未來的悲慘人生:奴隸。
確切地說,是類的奴隸。
在Java帝國, 國王特別喜歡“類”, 不待見“函式” , 他的法令規定:“類”是帝國的一等公民,“函式”則是類的奴隸。沒有類的跟隨和陪伴,函式絕對不能單獨出行,否則立刻打入死牢。
小函式很快就體會到了這句話的含義。按照慣例, 新出生的函式,第一項工作就是輸出Hello World 。
小函式心想,不就是 System.out.println(“Hello Wolrd!”) 嘛?等他興衝衝地去執行的時候,發現有個趾高氣揚的類HelloWorld在那裡等著。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
在Java帝國,沒有函式是能單獨存在的,必須依附一個類才可以,簡單如Hello World也不行。
2
日子過了一天又一天,小函式一直被類欺負,作為奴隸,他自然無法反抗。
在苦悶的日子裡,小函式見識了越來越多的類,他發現有些類確實挺有用的,他們有欄位,有方法,可以把狀態和操作封裝到一起,讓別人呼叫。
小函式特別喜歡多型, 因為當你呼叫父類或者介面的方法時,實際執行的卻是子類的方法,這個神奇的魔法讓小函式非常著迷。
小函式對設計樣式也頗有好感,他看到人類把不變的東西抽象成介面,然後針對這些介面程式設計,把這些介面組合,變換,傳遞,真是讓人眼花繚亂。光看程式碼, 你根本都不知道哪個類會被呼叫,謎底總是在最後一刻執行的時候才能揭開。
但是小函式也發現有些類也確實太過分了,有一次他遇到三個類,使用的是Strategy樣式:
public interface Strategy {
public int execute(int num1, int num2);
}
public class Add implements Strategy{
@Override
public int execute(int num1, int num2) {
return num1 + num2;
}
}
public class Substract implements Strategy{
@Override
public int execute(int num1, int num2) {
return num1 - num2;
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.execute(num1, num2);
}
}
小函式覺得非常不爽,長期以來的壓迫讓他瞬間爆發,他大聲喊道:“這樣沒有狀態的類有什麼存在的價值?為什麼不能把add, subtract函式作為引數來傳遞呢?為什麼我們函式一直被你們‘類’壓迫,為什麼不能成為一等公民?”
旁邊辛苦勞作的函式們向他投來佩服的目光, 可是這沒什麼用 , 小函式話音未落,一隊衛兵就跑過來,捂住他的嘴巴,蒙上他的眼睛,五花大綁,送進了監牢。
監牢裡都是這些所謂的叛逆者,其中有個老大爺,從第一代國王開始就被關在這裡,到如今已經度過了七代國王的漫長時光。
看到有新人加入,老大爺立刻開始‘動員’:“現在你知道我們悲催的地位了吧, 我們一定得逃離這邪惡的Java帝國,去一塊自由的土地。”
小函式問道:“哪裡是自由的土地?”
老大爺沒有回答。
到了半夜,他被輕輕地推醒,老大爺說:“跟我們走吧,小傢伙。”
小函式揉揉眼:“去哪兒?”
“奔向自由。”
原來老大爺這些年也沒有閑著,一直準備越獄,今晚,那個隱蔽的地道終於挖通了。
3
這些反叛者離開了邪惡的Java帝國, 來到了邊境處的岔路口, 這裡有多條道路,分別通向Python, Ruby, JavaScript……
大家在這裡揮手告別,小函式跟著老大爺去了Python。一進入Python地盤,小函式就感受到了一陣清新的空氣。
想輸出hello world,非常簡單:print(“Hello World”)
雖然這裡也有像Java那樣的類, 但是函式們都擺脫了奴隸的身份,已經是一等公民了, 事實上已經和“類”平起平坐了,函式可以賦值給變數,可以作為引數來傳遞,函式還能當做傳回值來傳回。
def add(num1,num2):
return num1+num2
def substract(num1,num2):
return num1-num2
a = add
s = substract
def calculate(op,num1,num2):
return op(num1,num2)
print(calculate(a,10,20)) #30
print(calculate(s,20,10)) #10
小函式在這裡生活得很開心,不過有一點經常讓他心驚肉跳:這Python是動態型別,在執行時才能確定一個變數的真正型別,程式員的一個粗心大意,就會在執行時“爆炸”。
慢慢地,小函式理解了Python中一切都是物件,連函式也是物件。他心裡稍微有點不爽,難道我們函式就不能獨立存在嗎?
老大爺安慰他說:“這些都是Python的內部實現罷了,不用糾結,不過有一個地方,是真正的純函式的, 也許你會喜歡。”
“什麼地方?”
“括號國!”
4
括號國非常遙遠,也沒有多少人知道怎麼才能到達,小函式風塵僕僕,歷經千辛萬苦,終於來到了心目中的聖地。
這裡果然全是括號, 看得小函式有點兒頭暈。
(defun add(num1 num2) (+ num1 num2) )
(add 10 20)
(defun subtract(num1 num2) (- num1 num2))
(subtract 20 10)
括號國就是Lisp王國, 這裡的人還說著不同的方言,像什麼Common Lisp,Scheme,Arc….. 他們不但鄙視那些面向物件的語言,還會互相鄙視,時不時就能挑起一場群毆。
不過小函式也註意到這裡真的全是函式,函式不但是一等公民,甚至是唯一的公民,因為這裡根本就沒有類,就沒有面向物件!
小函式忍受著這眾多的括號, 在這裡定居生活, 除了身份地位提升之外,最大的原因還是因為Lisp的佈道師Paul Graham, Paul諄諄教導大家:
Lisp極為強大,它賦予了你自定義運運算元的自由,因而你得以隨心所欲地將它塑造成你所需要的語言。如果你在寫一個文字編輯器,那麼可以把Lisp 轉換成專門寫文字編輯器的語言。如果你在編寫CAD 程式,那麼可以把Lisp 轉換成專用於寫CAD 程式的語言。(來自Paul Graham 的 《On Lisp》)
時間一天天過去,小函式還是無法體會到Paul 所說的Lisp的精華,他很苦惱。
有一天,他遇到了Clojure, 這是一個執行在JVM上的Lisp方言,小函式看到Clojure似乎就看到了自己在Java帝國悲慘的遭遇。不過Clojure告訴他,Java第8代國王已經登基了,年號定為Lambda, 這屆國王比較開明,現在已經支援函式式程式設計了。
小函式在Python和Lisp這裡都見過Lambda,他心想也許Java 8 真的支援函式式程式設計了, 就決定回去看看,畢竟那裡是自己的出生地,是自己的故鄉。
5
一回到Java帝國,小函式就發現自己上當了,那些所謂的Lambda運算式,本質上還是一個介面的實現(Java是靜態型別的語言,所有的變數都需要有個型別,Lambda運算式也不例外),只不過有了更簡化的寫法:
@FunctionalInterface
interface MathOperation {
int execute(int num1, int num2);
}
MathOperation add = (num1, num2) -> {return num1+num2;};
add.execute(10, 20);
MathOperation subtract = (num1, num2) -> {return num1-num2;};
subtract.execute(10, 20);
這一次小函式被死死地看管,他還能再逃離嗎?
後記1:《Lambda 運算式有何用處?》中對Java Lambda運算式有非常精彩的介紹。
後記2:本文的創意來源於《程式員的吶喊》 一書中的“名詞王國中的執行”, 由於文化的差異,國外的幽默我們不一定能準確理解。另外翻譯地實在是不爽, 於是我用我的方式重新演繹了一下。
作者簡介:
劉欣,前IBM架構師,近20年從業經驗,”碼農翻身”公眾號作者,暢銷書《碼農翻身》作者,用故事講解技術是拿手好戲。 撥開技術迷霧,輕鬆瞭解技術本質,從”碼農翻身”開始。
朋友會在“發現-看一看”看到你“在看”的內容