Lambda 表達式,Java中應用Lambda 表達式

1、Lambda 表達式javascript

簡單來講,編程中提到的 lambda 表達式,一般是在須要一個函數,可是又不想費神去命名一個函數的場合下使用,也就是指匿名函數。html

連接:知乎java

先舉一個普通的 Python 例子:將一個 list 裏的每一個元素都平方:express

map( lambda x: x*x, [y for y in range(10)] )

這段代碼表達的意思和下面的意思同樣:編程

def sq(x):
    return x * x

map(sq, [y for y in range(10)])
若是這個函數只會使用一次的話。並且第一種寫法實際上更易讀,由於那個映射到列表上的函數具體是要作什麼,很是一目瞭然。若是你仔細觀察本身的代碼,會發現這種場景其實很常見:你在某處就真的只須要一個能作一件事情的函數而已,連它叫什麼名字都可有可無。Lambda 表達式就能夠用來作這件事。
進一步講,匿名函數本質上就是一個函數,它所抽象出來的東西是一組運算。這是什麼意思呢?類比:
a = [1, 2, 3]

閉包

f = lambda x : x + 1

等號右邊的東西徹底能夠脫離等號左邊的東西而存在,等號左邊的名字只是右邊之實體的標識符。若是你能習慣 [1, 2, 3] 單獨存在,那麼 lambda x : x + 1 也能單獨存在其實也就不難理解了,它的意義就是給「某個數加一」這一運算自己。編程語言

如今回頭來看 map() 函數,它能夠將一個函數映射到一個可枚舉類型上面。沿用上面給出的 a 和 f,能夠寫:
map(f, a)

也就是將函數 f 依次套用在 a 的每個元素上面,得到結果 [2, 3, 4]。如今用 lambda 表達式來替換 f,就變成:
map( lambda x : x + 1, [1, 2, 3] )

這樣的寫法時,你會發現本身若是能將「遍歷列表,給遇到的每一個元素都作某種運算」的過程從一個循環裏抽象出來成爲一個函數 map,而後用 lambda 表達式將這種運算做爲參數傳給 map 的話,考慮事情的思惟層級會高出一些來,須要顧及的細節也少了一點。ide

 

2、Java中應用Lambda 表達式函數式編程

這一部分會介紹 Java8 Lambda 表達式產生的背景和用法,以及 Lambda 表達式與匿名類的不一樣這些內容,函數

首先看一個Java中匿名內部類的示例:

button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
    System.out.println("The button was clicked using old fashion code!");
}
});

這是使用匿名內部類的方法向一個 UI 組件添加 ActionListener,也能夠寫成:

button.addActionListener( (e) -> {
    System.out.println("The button was clicked. From Lambda expressions !");
});

後一種方式就是採用了Lambda表達式的方法來進行相同的操做。

爲何 Java 須要 Lambda 表達式?

若是忽視註解(Annotations)、泛型(Generics)等特性,自 Java 語言誕生時起,它的變化並不大。Java 一直都致力維護其對象至上的特徵,在使用過 JavaScript 之類的函數式語言以後,Java 如何強調其面向對象的本質,以及源碼層的數據類型如何嚴格變得更加清晰可感。其實,函數對 Java 而言並不重要,在 Java 的世界裏,函數沒法獨立存在。在函數式編程語言中,函數是一等公民,它們能夠獨立存在,你能夠將其賦值給一個變量,或將他們當作參數傳給其餘函數。JavaScript 是最典型的函數式編程語言。點擊此處以及此處能夠清楚瞭解 JavaScript 這種函數式語言的好處。函數式語言提供了一種強大的功能——閉包,相比於傳統的編程方法有不少優點,閉包是一個可調用的對象,它記錄了一些信息,這些信息來自於建立它的做用域。Java 如今提供的最接近閉包的概念即是 Lambda 表達式,雖然閉包與 Lambda 表達式之間存在顯著差異,但至少 Lambda 表達式是閉包很好的替代者。

Lambda表達式:

Lambda 表達式是一種匿名函數(對 Java 而言這並不徹底正確,但如今姑且這麼認爲),簡單地說,它是沒有聲明的方法,也即沒有訪問修飾符、返回值聲明和名字。

你能夠將其想作一種速記,在你須要使用某個方法的地方寫上它。當某個方法只使用一次,並且定義很簡短,使用這種速記替代之尤爲有效,這樣,你就沒必要在類中費力寫聲明與方法了。

Java 中的 Lambda 表達式一般使用 (argument) -> (body) 語法書寫,例如:

(arg1, arg2...) -> { body }

(type1 arg1, type2 arg2...) -> { body }

或者能夠寫做:

(int a, int b) -> {  return a + b; }

() -> System.out.println("Hello World");

(String s) -> { System.out.println(s); }

() -> 42

() -> { return 3.1415 };
  • 一個 Lambda 表達式能夠有零個或多個參數
  • 參數的類型既能夠明確聲明,也能夠根據上下文來推斷。例如:(int a)(a)效果相同
  • 全部參數需包含在圓括號內,參數之間用逗號相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
  • 空圓括號表明參數集爲空。例如:() -> 42
  • 當只有一個參數,且其類型可推導時,圓括號()可省略。例如:a -> return a*a
  • Lambda 表達式的主體可包含零條或多條語句
  • 若是 Lambda 表達式的主體只有一條語句,花括號{}可省略。匿名函數的返回類型與該主體表達式一致
  • 若是 Lambda 表達式的主體包含一條以上語句,則表達式必須包含在花括號{}中(造成代碼塊)。匿名函數的返回類型與代碼塊的返回類型一致,若沒有返回則爲空

使用Lambda表達式後,線程能夠經過如下方法初始化:

//舊方法:
new Thread(new Runnable() {
@Override
public void run() {
    System.out.println("Hello from thread");
}
}).start();

//新方法:
new Thread(
() -> System.out.println("Hello from thread")
).start();
相關文章
相關標籤/搜索