Java8與Scala中的Lambda表達(dá)式深入講解
前言
最近幾年Lambda表達(dá)式風(fēng)靡于編程界。很多現(xiàn)代編程語(yǔ)言都把它作為函數(shù)式編程的基本組成部分?;贘VM的編程語(yǔ)言如Scala、Groovy及Clojure把它作為關(guān)鍵部分集成在語(yǔ)言中。而如今,(最終)Java 8也加入了這個(gè)有趣的行列。
Java8 終于要支持Lambda表達(dá)式!自2009年以來(lái)Lambda表達(dá)式已經(jīng)在Lambda項(xiàng)目中被支持。在那時(shí)候,Lambda表達(dá)式仍被稱為Java閉包。在我們進(jìn)入一些代碼示例以前,先來(lái)解釋下為什么Lambda表達(dá)式在Java程序員中廣受歡迎。
1、為什么使用Lambda表達(dá)式
Lambda表達(dá)式通常使用在圖形用戶界面(GUI)的開(kāi)發(fā)中。一般來(lái)說(shuō),GUI編程將程序行為和事件做連接。比如,當(dāng)用戶按下一個(gè)按鈕(觸發(fā)一個(gè)事件),你的程序就需要去執(zhí)行某些行為,可能是將一些數(shù)據(jù)儲(chǔ)存到一個(gè)數(shù)據(jù)存儲(chǔ)器中。在Swing中,可以使用ActionListener來(lái)實(shí)現(xiàn):
class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e) { //do something } } class UIBuilder { public UIBuilder() { button.addActionListener(new ButtonHandler()); } }
這個(gè)例子表明了 ButtonHandler 類作為一個(gè)回調(diào)替換的用法。在這里 ButtonHandler 類僅包含 ActionListener 接口定義的 actionPerformed 方法。我們可以使用匿名內(nèi)部類來(lái)簡(jiǎn)化代碼:
class UIBuilder { public UIBuilder() { button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { //do something } }) } }
這樣代碼簡(jiǎn)潔多了。更仔細(xì)的去看代碼時(shí),就會(huì)發(fā)現(xiàn)我們還創(chuàng)建一個(gè)只生成一個(gè)實(shí)例的類,而這個(gè)實(shí)例也僅僅持有一個(gè)獨(dú)立的方法。這恰好是Lambda表達(dá)式所能解決的其中一類問(wèn)題。
2、Lambda表達(dá)式代替函數(shù)
一個(gè)lambda表達(dá)式從字面上講就是一個(gè)函數(shù)。它定義了一個(gè)函數(shù)的輸入?yún)?shù)和函數(shù)體。Java 8 中的,lambda表達(dá)式語(yǔ)法尚未確定,不過(guò)大致應(yīng)該類似這個(gè)樣子的:
(type parameter) -> function_body
一個(gè)具體的例子:
(String s1, String s2) -> s1.length() - s2.length();
這個(gè)lambda表達(dá)式用來(lái)計(jì)算兩個(gè)字符串的長(zhǎng)度差。還有一些擴(kuò)展的語(yǔ)法,比如避免參數(shù)的類型定義(我們馬上見(jiàn)看到例子)還有使用{和}來(lái)支持多行定義。
Collections.sort()
方法是lambda表達(dá)的理想例子。它允許我們將字符串按照長(zhǎng)度排序:
List<String> list = Array.asList("loooooong", "short", "tiny"); Collections.sort(list, (String s1, String s2) -> s1.length() - s2.length()); > "tiny", "short", "loooooong".
所以,不像現(xiàn)在java必須要求的向sort方法輸入一個(gè)已經(jīng)實(shí)現(xiàn)的Comparator(比較器)而是傳送一個(gè)lambda表達(dá)式我們就可以得到相同的結(jié)果。
3、Lambda表達(dá)式代替閉包
lambda表達(dá)式有許多有趣的特性。其中之一是,它們是閉包。一個(gè)閉包允許函數(shù)訪問(wèn)直接詞法作用域之外的變量。
String outer = "java 8" (String s1) -> s1.length() - outer.length()
在例子中,lambda表達(dá)式訪問(wèn)了字符串 outer 這個(gè)作用域之外定義的變量。對(duì)于內(nèi)聯(lián)閉包來(lái)說(shuō)這是很難做到的。
4、Lambda表達(dá)式也支持類型推論
類型推論是java 7 引入的但它同樣適用于lambda表達(dá)式。簡(jiǎn)單來(lái)說(shuō),類型推論意味著程序員可以在任意一個(gè)編譯器能夠自動(dòng)推斷出類型的地方省略類型定義。
如果類型推論能夠應(yīng)用到前面的排序lambda表達(dá)式上,那么它就能寫成下面的樣子:
List<String> list = Arrays.asList(...); Collections.sort(list, (s1, s2) -> s1.length()-s2.length());
就像你所見(jiàn)到的一樣,參數(shù)s1和s2的類型被省略了。因?yàn)榫幾g器知道list是一個(gè)字符串集合,它知道被用來(lái)作為比較器的lambda表達(dá)式必定是相同的類型。因此,這個(gè)類型不需要顯式地聲明,即使你有這么做的自由。
類型推論的主要優(yōu)勢(shì)就是減少樣板代碼,如果編譯器可以為我們識(shí)別類型,為什么我們必須自己定義它們。
5、珍愛(ài)Lambda表達(dá)式,遠(yuǎn)離匿名內(nèi)部類
我們來(lái)體會(huì)下,為何lambda表達(dá)式和類型推論有助于簡(jiǎn)化我們前面所提到的回調(diào)例子:
class UIBuilder { public UIBuilder() { button.addActionListener(e -> //process ActionEvent e) } }
我們下載直接傳送一個(gè)lambda表達(dá)式進(jìn)入 addActionListener 方法來(lái)代替前面定義的持有回調(diào)方法的類。除了減少模板代碼和提高可讀性以外,它使我們直接表達(dá)我們唯一感興趣的事情:處理事件。
在我們了解lambda表達(dá)式更多優(yōu)勢(shì)之前,先來(lái)看看在Scala中的lambda表達(dá)式副本。
6、Scala中的Lambda表達(dá)式
在函數(shù)式編程中,函數(shù)是基本的構(gòu)造塊。Scala融合了java中的面向?qū)ο缶幊毯秃瘮?shù)式編程。在Scala中,一個(gè)lambda表達(dá)式是種叫做“函數(shù)”或者“函數(shù)文本”。Scala中的函數(shù)屬于一等公民。它們可以被分配給vals或者vars(最終變量或者非最終變量),它們可以作為其他函數(shù)的參數(shù),也可以組合成新的函數(shù)。
在Scala中一個(gè)函數(shù)文本寫成如下形式:
(argument) => //funtion body
舉例來(lái)說(shuō),前面提到的java 用來(lái)計(jì)算兩個(gè)字符串長(zhǎng)度差的 lambda 表達(dá)式,在Scala中寫作如下:
(s1: String, s2 :String) => s1.length - s2.length
Scala中的函數(shù)文本也是閉包。它可以訪問(wèn)在直接詞法作用域之外定義的變量。
val outer =10 val myFuncLiteral = (y: Int) => y * outer val result = myFuncLiteral(2) > 20
這個(gè)例子結(jié)果是20.
正如你所見(jiàn),我們將函數(shù)文本分配給了變量 myFuncLiteral。
java 8 的lambda表達(dá)式和Scala的函數(shù)文本在語(yǔ)法和語(yǔ)義上的相似性是十分明顯的。從語(yǔ)義上講它們是相同的,而語(yǔ)法上的唯一不同就是箭頭符號(hào)(java8 ->, scala =>)和我們沒(méi)有提到的簡(jiǎn)化符號(hào)。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- Java8新特性lambda表達(dá)式有什么用(用法實(shí)例)
- Java8新特性Lambda表達(dá)式的一些復(fù)雜用法總結(jié)
- Java8新特性之Lambda表達(dá)式淺析
- Java8中l(wèi)ambda表達(dá)式的應(yīng)用及一些泛型相關(guān)知識(shí)
- Java8 Lambda表達(dá)式詳解及實(shí)例
- Java8中的 Lambda表達(dá)式教程
- Java8中的lambda表達(dá)式入門教程
- Java8 新特性Lambda表達(dá)式實(shí)例詳解
- 30分鐘入門Java8之lambda表達(dá)式學(xué)習(xí)
- Java8中Lambda表達(dá)式的理解與應(yīng)用
相關(guān)文章
詳解SpringBoot 使用Spring Initializr 快速構(gòu)建工程(官方推薦)
本篇文章主要介紹了SpringBoot 使用Spring Initializr 快速構(gòu)建工程(官方推薦),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10Springboot如何實(shí)現(xiàn)自定義異常數(shù)據(jù)
這篇文章主要介紹了Springboot如何實(shí)現(xiàn)自定義異常數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09spring事務(wù)里面開(kāi)啟線程插入報(bào)錯(cuò)了是否會(huì)回滾
這篇文章主要介紹了spring事務(wù)里面開(kāi)啟線程插入,報(bào)錯(cuò)了是否會(huì)回滾?這是小編遇到一道面試題,題目大概是這個(gè)樣子,今天抽空通過(guò)示例代碼給大家分析下,需要的朋友可以參考下2023-04-04Spring的同一個(gè)服務(wù)會(huì)加載多次的問(wèn)題分析及解決方法
這篇文章主要介紹了Spring的同一個(gè)服務(wù)為什么會(huì)加載多次,我們先來(lái)梳理一下?Web?容器中如何加載?Bean,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10IntelliJ?IDEA?2022安裝注冊(cè)永久激活
java開(kāi)發(fā)工具IntelliJ?IDEA深受用戶喜愛(ài),很多朋友對(duì)這個(gè)idea開(kāi)發(fā)工具比較忠心,一旦有新版本發(fā)出,很多小伙伴就迫不及待的想更新,今天小編給大家?guī)?lái)了idea2022.1最新永久激活碼,親測(cè)有效,喜歡的朋友快來(lái)下載體驗(yàn)吧2022-08-08SpringBoot項(xiàng)目中日志管理與調(diào)優(yōu)指南
在 Spring Boot 開(kāi)發(fā)過(guò)程中,日志管理是開(kāi)發(fā)者必須掌握的重要技能之一,合理的日志配置不僅能幫助開(kāi)發(fā)者追蹤應(yīng)用程序的執(zhí)行流程、定位問(wèn)題,還能提升應(yīng)用程序的可維護(hù)性,本文將詳細(xì)探討 Spring Boot 項(xiàng)目中日志管理的常見(jiàn)問(wèn)題、解決方案以及最佳實(shí)踐2024-10-10