每天進步一點點!
在我們剛接觸Java時候,我們就被告知,Java是一門靜態類型語言。
隨着開發技術的發展,出現了更多的動態語言,比如我們耳熟能詳的Groovy,List,Python,Ruby,JavaScript等。
這也就迫使Java需要做出改變,從jdk7開始,Java提供了對動態類型語言的支持,引入了invokedymanic指令提供對動態類型語言的支持。
隨之在jdk8開始,推出了lambda表達式,來實現動態類型語言特性。
動態類型語言這個詞已經活躍了很多年了,聽起來比較複雜,其實也挺複雜的。
首先我們看一下什麼是動態類型語言?簡單地說,靜態類型語言在編譯期進行類型檢查,而動態類型語言在運行期進行類型檢查。
動態類型語言的特點,說的再直白一點——“變量無類型而變量值纔有類型”。
如下圖所示,在Java方法中,定義的變量a,b,c的類型是確定的,就是int型。
下面我們再看一下JavaScript的代碼,如果不通過執行的話,我們是無法確定element到底是什麼類型的。
知道了兩種類型的區別,再簡單對比一下兩種類型的優缺點:
靜態類型語言:提供嚴謹的類型檢查,有利於穩定性和功能擴展,適合大型系統。
動態類型語言:代碼編寫更加靈活,開發效率提升。
既然提到了lambda表達式,那就讓我們簡單地一起來學習一下。
lambda表達式的語法格式:(parameters) -> expression或(parameters) ->{ statements; }。
用法和一些需要注意的地方,我們通過下面幾個例子感受一下。
1. lambda表達式可以用來代替匿名內部類
如下圖所示,我們寫了一個test1()方法,用來創建一個線程,線程中包含一個打印操作。
我們便可以使用test2()中一行代碼作爲代替,你還別說,確實些起來更加簡潔了!
注意了,我們可以看到,這裏參數列表爲空,lambda表達式是可以沒有參數的!
還有一個地方,那就是如果主題包含了一個語句就不用寫花括號{}了。
前面我們說過,引入了invokedymanic指令提供對動態類型語言的支持,我們不妨打開字節碼文件看一眼,嗯,還好書上沒有騙我。
相對應地,常量池中的類型也變成了CONSTANT_Methodref_info。
2. lambda表達式可以用來實現接口
首先我們定義一個接口Inter,其中包含一個方法sayHello(),需要傳入參數name。
按照常規的做法,我們會寫一個實現類InterImpl用來實現Inter接口,並實現sayHello()方法。
然後通過創建對象,傳入參數,調用方法。
但是,假如使用lambda表達式怎麼寫呢?如下圖所示,簡單的令人髮指有木有!!!
好,這裏有第三個需要注意的地方了:當參數只有一個的時候,可以不用寫括號。
3. lambda表達式實現集合的遍歷
這個相信朋友都能看懂就不說什麼了,但是有一點前面已經提到過了,大家不要忽視了,參數str是沒有指定類型的。
4. 使用lambda表達式實現函數式編程
在Java 8中新增了一個類java.util.function.Predicate是支持函數式編程的。
最後要注意的一點:主體只有一個表達式編譯器會自動返回值,不需要寫return,但是多條的時候是需要的。
看了這麼多lambda表達式的例子,我們再來看一下書中提到了一種新的確定目標方法的類java.lang.invoke.MethodHandle:
我們打開看一眼,一共1457行,這一片一片的都是啥啊?幸虧筆者眼尖,在248行發現了“Usage examples”幾個大字,ctrl+c,ctrl+v複製到單元測試類中,就看一下前幾行吧。
mt中包含了方法的返回值類型(String)和參數類型數組。
mh中又增加member用來存儲對應的目標方法和執行指令:java.lang.String.replace(char,char)String/invokeSpecial
最後在invokeExact中調用了方法的執行,筆者這裏也只有拋磚引入,更加深入的使用方法,還有待於朋友們共同探討。
最後,依據筆者的經驗,動態類型語言可以用來寫工具類。
however,然鵝,並不建議在業務系統代碼中使用,可讀性真的有待商榷。
喜歡文章或想一起學習的朋友可以關注我,給我點贊,我將會持續更新,有什麼疑問或文中有不當之處請給我留言,真誠地希望能與大家一起交流探討,學習進步!