搜尋
首頁类库下载java类库Java Lambda表達式初探

Java Lambda表達式初探

Oct 09, 2016 am 10:24 AM

Java Lambda表達式初探

前言

本文受啟發於Trisha Gee在JavaOne 2016的主題演講Refactoring to Java 8。

Java 8已經發行兩年多,但很多人仍然在使用JDK7。對企業來說,技術上謹慎未必是壞事,但對個人學習而言,不去學習新科技就很可能被科技拋棄。 Java 8一個重要的變更是引入Lambda表達式(lambda expression),這聽起來似乎很牛,有種我雖然不知道Lambda表達式是什麼,但我仍然覺得很厲害的感覺。不要害怕,具體到語言層面上Lambda表達式不過是一種新的語法而已,有了它,Java將開啟函數式程式設計的大門。

為什麼需要Lambda表達式

不要糾結什麼是Lambda表達式、什麼是函數式程式設計。先來看看Java 8新的語法特性帶來的便利之處,相信你會過目不忘的。

在有Lambda表達式之前,要新建一個線程,需要這樣寫:

new Thread(new Runnable(){    @Override
    public void run(){
        System.out.println("Thread run()");
    }
}).start();

有Lambda表達式之後,則可以這樣寫:

new Thread(
        () -> System.out.println("Thread run()")
).start();

正如你所見,之前無用的模板代碼不見了!如上所示,Lambda表達式一個常見的用法是取代(某些)匿名內部類,但Lambda表達式的作用不限於此。

Lambda表達式的原理

剛接觸Lambda表達式可能覺得它很神奇:不需要宣告類別或方法的名字,就可以直接定義函數。但其實這只是編譯器給我們的一個小把戲,背後的原理並不難理解。以下是Lambda表達式幾種可能的書寫形式:

Runnable run = () -> System.out.println("Hello World");// 1ActionListener listener = event -> System.out.println("button clicked");// 2Runnable multiLine = () -> {// 3
    System.out.println("Hello ");
    System.out.println("World");
};
BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5

透過上例可以發現:

Lambda表達式是有類型的,賦值運算的左邊就是型別。 Lambda表達式的類型其實是對應介面的類型。

Lambda表達式可以包含多行程式碼,需要用大括號把程式碼區塊括起來,就像寫函數體一樣。

大多數時候,Lambda表達式的參數表可以省略型別,就像程式碼2和5一樣。這得歸功於javac的類型推導機制,編譯器可以根據上下文推導出類型資訊。

其實每個Lambda表達式都是原來匿名內部類別的簡寫形式,該內部類別實作了某個函數介面(Functional Interface)。所謂函數介面是指*新增了@FunctionalInterface標註,且內部只有一個介面函數的介面*。 Java是強類型語言,無論有沒有明確指明,每個變數和物件都必須有明確的類型,沒有明確指定的時候編譯器會嘗試確定類型。 Lambda表達式的類型就是對應函數介面的類型。

Lambda表達式和Stream

Lambda表達式的另一個重要用法,是和Stream一起使用。 Stream is a sequence of elements supporting sequential and parallel aggregate operations。 Stream就是一組元素的序列,支援對這些元素進行各種操作,而這些操作是透過Lambda表達式指定的。可以把Stream看作Java Collection的一種視圖,就像迭代器是容器的一種視圖那樣(但Stream不會修改容器中的內容)。下面例子展示了Stream的常見用法。

範例1

假設需要從一個字串清單中選出以數字開頭的字串並輸出,Java 7之前需要這樣寫:

List<String> list = Arrays.asList("1one", "two", "three", "4four");for(String str : list){    if(Character.isDigit(str.charAt(0))){
        System.out.println(str);
    }
}

而Java 8就可以這樣寫:

List<String> list = Arrays.asList("1one", "two", "three", "4four");
list.stream()// 1.得到容器的Steam
    .filter(str -> Character.isDigit(str.charAt(0)))// 2.选出以数字开头的字符串
    .forEach(str -> System.out.println(str));// 3.输出字符串

上述程式碼首先1 . 呼叫List.stream()方法得到容器的Stream,2. 然後呼叫filter()方法過濾出以數字開頭的字串,3. 最後呼叫forEach()方法輸出結果。

使用Stream有兩個明顯的好處:

減少了模板程式碼,只用Lambda表達式指明所需操作,程式碼語意更加明確、方便閱讀。

將外部迭代改成了Stream的內部迭代,方便了JVM本身對迭代過程做最佳化(例如可以並行迭代)。

例子2

假設需要從一個字串清單中,選出所有不以數字開頭的字串,將其轉換成大寫形式,並把結果放到新的集合當中。 Java 8書寫的程式碼如下:

List<String> list = Arrays.asList("1one", "two", "three", "4four");
Set<String> newList =
        list.stream()// 1.得到容器的Stream
        .filter(str -> !Character.isDigit(str.charAt(0)))// 2.选出不以数字开头的字符串
        .map(String::toUpperCase)// 3.转换成大写形式
        .collect(Collectors.toSet());// 4.生成结果集

上述代码首先1. 调用List.stream()方法得到容器的Stream,2. 然后调用filter()方法选出不以数字开头的字符串,3. 之后调用map()方法将字符串转换成大写形式,4. 最后调用collect()方法将结果转换成Set。这个例子还向我们展示了方法引用(method references,代码中标号3处)以及收集器(Collector,代码中标号4处)的用法,这里不再展开说明。

通过这个例子我们看到了Stream链式操作,即多个操作可以连成一串。不用担心这会导致对容器的多次迭代,因为不是每个Stream的操作都会立即执行。Stream的操作分成两类,一类是中间操作(intermediate operations),另一类是结束操作(terminal operation),只有结束操作才会导致真正的代码执行,中间操作只会做一些标记,表示需要对Stream进行某种操作。这意味着可以在Stream上通过关联多种操作,但最终只需要一次迭代。如果你熟悉Spark RDD,对此应该并不陌生。

结语

Java 8引入Lambda表达式,从此打开了函数式编程的大门。如果你之前不了解函数式编程,不必纠结于这个概念。编程过程中简洁明了的书写形式以及强大的Stream API会让你很快熟悉Lambda表达式的。

本文只对Java Lambda表达式的基本介绍,希望能够激发读者对Java函数式编程的兴趣。如果本文能够让你觉得Lambda表达式很好玩,函数式编程很有趣,并产生了进一步学习的欲望,那就再好不过了。文末参考文献中列出了一些有用的资源。


参考文献

http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
http://www.slideshare.net/trishagee/refactoring-to-java-8-devoxx-uk
《Java 8函数式编程 [英]沃伯顿》
https://www.oracle.com/javaone/speakers.html#gee


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器