日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记

發布時間:2024/1/17 java 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java Lambda 表達式(又名閉包 (Closure)/ 匿名函數 ) 筆記

根據 JSR 335, Java 終于在 Java 8 中引入了 Lambda 表達式。也稱之為閉包或者匿名函數。

JSR 335

所謂的 JSR (Java Specification Requests) 全稱叫做 Java 規范提案。簡單來說就是向 Java 社區提交新的 API 或 服務 請求的提案。這些提案將作為 Java 社區進行 Java 語言開發的需求,引導著開發的方向。

JSR 335 的提案內容摘要如下:

This JSR will extend the Java Programming Language Specification and the Java Virtual Machine Specification to support the following features:

  • ambda Expressions
  • SAM Conversion
  • Method References
  • Virtual Extension Methods

也就是如下幾點:

  • 支持 lambda 表達式。
  • 支持 SAM conversion 用來向前兼容。
  • 方法引用 Method References
  • Virtual Extension Methods
  • 在 Java 8 中,以上均已經實現, 以上內容下文均有介紹。
  • 為什么需要 Lambda 表達式?

    Lambda 表達式,其實就是代碼塊。

    原來怎么處理

    在具體了解 lambda 之前,我們先往后退一步,看看之前我們是如何處理這些代碼塊的!

    例子一

    當決定在單獨的線程運行某程序時,你這樣做的

    class Worker implements Runnable {public void run() {for (int i = 0; i < 1000; i++)doWork();}...}

    這樣執行:

    Worker w = new Worker(); new Thread(w).start();

    Worker 中包含了你要執行的代碼塊。

    例子二

    如果你想實現根據字符串長度大小來排序,而不是默認的字母順序,你可以自己來實現一個 Comparator 用來 Sort

    class LengthComparator implements Comparator<String> {public int compare(String first, String second) {return Integer.compare(first.length(), second.length());}}Arrays.sort(strings, new LengthComparator());

    ####例子三

    另外一個例子,我選的是 Android 中的點擊事件,同樣是 Java:

    button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, "Hello World!", Toast.LENGTH_SHORT).show();} });

    ###上面代碼有什么問題呢?###

    它們都太復雜了啊!

    上述例子都是在某個類中實現某個接口,然后傳遞到另外一個方法中作為參數,然后用來執行。

    但是本質上,他們要傳遞的就是接口中那一個方法的實現而已啊!有必要先創建類,再實例化,再傳遞給調用的位置嗎?

    因為 Java 是純面向對象的語言,像其他語言那樣隨隨便便傳個方法過來,那可不行,必須要這樣。
    在其他語言中你可能可以,但是,在Java 中,不可以。

    Java 設計人員為了 Java 的簡潔跟連貫性,一直拒絕為 Java 添加這種功能。(這也是我喜歡 Java 而不喜歡 Python 的原因啊!!!)

    經過多年的努力,開發人員終于找到了符合 Java 編程習慣的 Lambda 表達式!

    Lambda 表達式語法(Syntax)

    考慮下前面的例子:

    Integer.compare(first.length(), second.length())

    first 和 second 都是 String 類型,Java 是強類型的語言,必須指定類型:

    (String first, String second)-> Integer.compare(first.length(), second.length())

    看到沒有!第一個 Lambda 表達式誕生了!!輸入、輸出簡潔明了!

    為什么叫 Lambda 呢,這個很多年以前,有位邏輯學家想要標準化的表示一些可以被計算的數學方程(實際上存在,但是很難被表示出來),他就用 ? 來表示。

    重新介紹一下 Java 中 Lambda 表達式的格式:

    (參數) -> 表達式

    多返回值

    (String first, String second) -> {if (first.length() < second.length()) return -1;else if (first.length() > second.length()) return 1;else return 0;

    }

    如果計算的結果并不由一個單一的表達式返回(換言之,返回值存在多種情況),使用“{}”,然后明確指定返回值。

    (String first, String second) -> {if (first.length() < second.length()) return -1;else if (first.length() > second.length()) return 1;else return 0; }

    ###無參數

    如果沒有參數,則 “()”中就空著。

    () -> { for (int i = 0; i < 1000; i++) doWork(); }

    ###省略###

    Comparator<String> comp= (first, second) // Same as (String first, String second)-> Integer.compare(first.length(), second.length());

    這里,first 和 second 可以被推斷出是 String 類型,因為 是一個 String 類型的 Comparator。

    如果單個參數可以被推斷出,你連括號都可以省略:

    EventHandler<ActionEvent> listener = event ->System.out.println("Thanks for clicking!");// Instead of (event) -> or (ActionEvent event) ->

    ###修飾符

    你可以像對待其他方法一樣,annotation,或者 使用 final 修飾符

    (final String name) -> ...(@NonNull String name) -> ...

    永遠不要 定義 result 的類型,lambda 表達式總是從上下文中推斷出來的:

    (String first, String second) -> Integer.compare(first.length(), second.length())

    ###注意
    注意,在 lambda 表達式中,某些分支存在返回值,某些不存在返回值這樣的情況是不允許的。
    如 (int x) -> {if (x >= 0) return 1; }這樣是非法的。

    函數式接口 (Functional Interfaces/SAM)

    要介紹 Java 中 lambda 表達式的實現,需要知道什么是 函數式接口。

    什么叫作函數式接口呢 (SAM)?

    函數式接口指的是只定義了唯一的抽象方法的接口(除了隱含的 Object 對象的公共方法), 因此最開始也就做 SAM 類型的接口(Single Abstract Method)。

    Lambda 表達式 向前兼容 這些接口。

    Comparable

    舉個例子 Array.sort:

    Arrays.sort(words,(first, second) -> Integer.compare(first.length(), second.length()));

    Array.sort() 方法收到一個實現了 Comparable接口的實例。

    其實可以把 Lambda 表達式想象成一個方法,而非一個對象,一個可以傳入一個接口的方法。

    OnClickListener

    再舉個例子

    button.setOnClickListener(event ->System.out.println("Thanks for clicking!"));

    你看,是不是更易讀了呢?

    Lambda 表達式能夠向前兼容這些 interfaces, 太棒了! 那 Lambda 表達式還能干什么呢?

    實際上,將函數式接口轉變成 lambda 表達式是你在 Java 中 唯一 能做的事情。


    Why ?!!

    在其他的語言中,你可以定義一些方便的方法類型,但在 Java 中,你甚至不能將一個 Lambda 表達式賦值給類型為 Object 的變量,因為 Object 變量不是一個 Functional Interface。

    Java 的設計者們堅持使用熟悉的 interface 概念而不是為其引入新的 方法類型。

    (這里我還要為設計者點贊!謹慎的設計,一方面降低了初學者的門檻,一方面方便了高級用戶的使用。對比 python2 和 python3,升級的不兼容讓很多人一直停留在 python2)

    Method References

    能不能再簡潔一點?有的時候我們所要做的事情不過是調用其他類中方法來處理事件。

    button.setOnClickListener(event -> System.out.println(event));

    如果這樣呢?

    button.setOnAction(System.out::println);

    表達式 System.out::println 屬于一個方法引用(method reference), 相當于 lambda 表達式 x -> System.out.println(x)

    再舉個例子,如果你想對字符串不管大小寫進行排序, 就可以這樣寫!

    Arrays.sort(strings, String::compareToIgnoreCase)

    如上所見 ::操作符將方法名與實例或者類分隔開??傮w來說,又如下的規則:

    • object::instanceMethod
    • Class::staticMethod
    • Class::instanceMethod

    值得指出的是, this和 super 關鍵字可以在其中使用:

    class Greeter {public void greet() {System.out.println("Hello, world!");}}

    .

    class ConcurrentGreeter extends Greeter {public void greet() {Thread t = new Thread(super::greet);t.start();} }

    構造方法引用 Constructor References

    跟上一個差不多,畢竟 構造方法 也是方法啊!!不過方法名字為 new 。

    但是!這個構造方法引用有一個牛逼的地方!

    你知道 Array 是不能使用范型的對吧!(什么,你不知道?看看這里 http://stackoverflow.com/ques... 你沒有辦法創建一個類型為 T 的 Array 。 new T[n] 將會被覆蓋為 new Object[n]。

    假設我們想要一個包含 buttons 的 Array。Stream interface 可以返回一個 Object array。

    Object[] buttons = stream.toArray();

    不不不,我們可不想要 Object。Stream 庫使用 構造方法引用解決了這個問題:

    Button[] buttons = stream.toArray(Button[]::new);

    變量作用域

    注意到我們在題目中寫著 閉包(closure), 實際上,閉包的定義是: 引用了自由變量的函數。

    在之前,如果需要在匿名類的內部引用外部變量,需要將外部變量定義為 final ,現在有了 lambda 表達式,你不必再這么做了。但同樣需要保證外部的自由變量不能在 lambda 表達式中被改變。

    這是什么意思呢? 不需要定義為 final,也不能改?

    其實理解起來很簡單,Java 8 中,不需要定義為 final ,但你其實可以直接把他當作 final,不要試圖修改它就行了。

    即便你用內部類,現在也無需定義為 final 了。

    參考 StackOverFlow 鏈接: http://stackoverflow.com/ques...

    Default Methods

    由于歷史原因,像是類似 Collection 這種接口,如果進行添加接口的話,那將會造成之前的代碼出錯。

    Java 想了一個一勞永逸的方法解決這個問題, 使用 default 修飾符來提供默認的實現

    比如 Collection 接口的源代碼:

    default void remove() {throw new UnsupportedOperationException("remove"); }

    當沒有 override remove 這個方法是,調用的時候返回 UnsupportedOperationException 錯誤。

    Static Methods in Interfaces

    Java 8 中,你可以在接口中添加靜態方法了。 看起來好像并不符合接口的定義了。

    一般用來生成一個簡單實現該 interface 的實例。

    參考鏈接:

    JSR 335: Lambda Expressions for the JavaTM Programming Language
    Java 8 新特性概述
    Lambda Expressions in Java 8

    總結

    以上是生活随笔為你收集整理的Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。