Lambda

前言

Java11前兩天都發(fā)布了,而自己Java8還沒搞明白,真是羞為稱自己為Java程序員。今天就讓我們來(lái)通俗易懂的聊一聊Java8中的Lambda表達(dá)式~

簡(jiǎn)單上手

u=20823480,933902871&fm=173&app=25&f=JPEG.jpg

通過(guò)Lamda表達(dá)式,可以變換為:

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

針對(duì)這種實(shí)行,我們?cè)趺蠢斫饽??其?shí)很簡(jiǎn)單,上看一下上述lambda表達(dá)式的語(yǔ)法:() -> {} (): 括號(hào)就是接口方法的括號(hào),接口方法如果有參數(shù),也需要寫參數(shù)。只有一個(gè)參數(shù)時(shí),括號(hào)可以省略。-> : 分割左右部分的,沒啥好講的。{} : 要實(shí)現(xiàn)的方法體。只有一行代碼時(shí),可以不加括號(hào),可以不寫return。

不過(guò)看到這里我相信有些小伙伴已經(jīng)許意識(shí)到了,如果接口中有多個(gè)方法時(shí),那么按照上面的邏輯lambda表達(dá)式恐怕沒辦法表示了。的確是這樣,并非任何接口都支持lambda表達(dá)式。

而適用于lambda表達(dá)式的接口稱之為函數(shù)型接口。說(shuō)白了,函數(shù)型接口就是只有一個(gè)抽象方法的接口。

函數(shù)式接口

其實(shí)之前在講Lambda表達(dá)式的時(shí)候提到過(guò),所謂的函數(shù)式接口,當(dāng)然首先是一個(gè)接口,然后就是在這個(gè)接口里面只能有一個(gè)抽象方法。

這種類型的接口也稱為SAM接口,即Single Abstract Method interfaces。

1.1、函數(shù)式接口基本語(yǔ)法

它們主要用在Lambda表達(dá)式和方法引用(實(shí)際上也可認(rèn)為是Lambda表達(dá)式)上。

如定義了一個(gè)函數(shù)式接口如下:


u=2729990849,1446984129&fm=173&app=25&f=JPEG.jpg

那么就可以使用Lambda表達(dá)式來(lái)表示該接口的一個(gè)實(shí)現(xiàn)(注:JAVA 8 之前一般是用匿名類實(shí)現(xiàn)的):

GreetingService greetService1 = message -> System.out.println("Hello " + message);

1.2、FunctionalInterface注解

關(guān)于@FunctionalInterface注解Java 8為函數(shù)式接口引入了一個(gè)新注解@FunctionalInterface,主要用于編譯級(jí)錯(cuò)誤檢查,加上該注解,當(dāng)你寫的接口不符合函數(shù)式接口定義的時(shí)候,編譯器會(huì)報(bào)錯(cuò)。

正確例子,沒有報(bào)錯(cuò):


u=2729990849,1446984129&fm=173&app=25&f=JPEG.jpg

1.3、用法提醒

ERROR:接口中包含了兩個(gè)抽象方法,違反了函數(shù)式接口的定義,IDE會(huì)直接報(bào)錯(cuò)。

Tips:加不加@FunctionalInterface對(duì)于接口是不是函數(shù)式接口沒有影響,該注解知識(shí)提醒編譯器去檢查該接口是否僅包含一個(gè)抽象方法

1.4、默認(rèn)方法

函數(shù)式接口里是可以包含默認(rèn)方法,因?yàn)槟J(rèn)方法不是抽象方法,其有一個(gè)默認(rèn)實(shí)現(xiàn),所以是符合函數(shù)式接口的定義的;


u=2547916558,3030871120&fm=173&app=25&f=JPEG.jpg

1.5、靜態(tài)方法

函數(shù)式接口里是可以包含靜態(tài)方法,因?yàn)殪o態(tài)方法不能是抽象方法,是一個(gè)已經(jīng)實(shí)現(xiàn)了的方法,所以是符合函數(shù)式接口的定義的;

如下代碼不會(huì)報(bào)錯(cuò):


u=2268955634,2131712240&fm=173&app=25&f=JPEG.jpg

1.6、Object里的public方法

函數(shù)式接口里是可以包含Object里的public方法,這些方法對(duì)于函數(shù)式接口來(lái)說(shuō),不被當(dāng)成是抽象方法(雖然它們是抽象方法);因?yàn)槿魏我粋€(gè)函數(shù)式接口的實(shí)現(xiàn),默認(rèn)都繼承了Object類,包含了來(lái)自java.lang.Object里對(duì)這些抽象方法的實(shí)現(xiàn);

如下代碼不會(huì)報(bào)錯(cuò):


u=1494202482,2752892781&fm=173&app=25&f=JPEG.jpg

進(jìn)階

有了上面的基礎(chǔ),我們稍稍聊一些深入的lambda表達(dá)式。lambda表達(dá)式還有兩種簡(jiǎn)化代碼的手段,它們是方法引用、構(gòu)造引用。

方法引用是什么呢?如果我們要實(shí)現(xiàn)接口的方法與另一個(gè)方法A類似,(這里的類似是指參數(shù)類型與返回值部分相同),我們直接聲明A方法即可。也就是,不再使用lambda表達(dá)式的標(biāo)準(zhǔn)形式,改用高級(jí)形式。無(wú)論是標(biāo)準(zhǔn)形式還是高級(jí)形式,都是lambda表達(dá)式的一種表現(xiàn)形式。

Function function1 = (x) -> x;Function function2 = String::valueOf;

對(duì)比Function接口的抽象方法與String的value方法,可以看到它們是類似的。


u=1323023801,4053429754&fm=173&app=25&f=JPEG.jpg

方法引用的語(yǔ)法:

對(duì)象::實(shí)例方法類::靜態(tài)方法類::實(shí)例方法

前兩個(gè)很容易理解,相當(dāng)于對(duì)象調(diào)用實(shí)例方法,類調(diào)用靜態(tài)方法一樣。只是第三個(gè)需要特殊說(shuō)明。

Compare<Boolean> c = String::equals;

也就是“類::實(shí)例方法”的形式。

構(gòu)造引用

u=1618868181,3291930072&fm=173&app=25&f=JPEG.jpg

提煉一下構(gòu)造引用的語(yǔ)法:類名::new


u=492617495,3453585447&fm=173&app=25&f=JPEG.jpg

變量作用域

lambda 表達(dá)式只能引用標(biāo)記了 final 的外層局部變量,這就是說(shuō)不能在 lambda 內(nèi)部修改定義在域外的局部變量,否則會(huì)編譯錯(cuò)誤。

在 Java8Tester.java 文件輸入以下代碼:

public class Java8Tester {
 
   final static String salutation = "Hello! ";
   
   public static void main(String args[]){
      GreetingService greetService1 = message -> 
      System.out.println(salutation + message);
      greetService1.sayMessage("Runoob");
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
}

執(zhí)行以上腳本,輸出結(jié)果為:

Hello! Runoob

我們也可以直接在 lambda 表達(dá)式中訪問(wèn)外層的局部變量:

public class Java8Tester {
    public static void main(String args[]) {
        final int num = 1;
        Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
        s.convert(2);  // 輸出結(jié)果為 3
    }
 
    public interface Converter<T1, T2> {
        void convert(int i);
    }
}

lambda 表達(dá)式的局部變量可以不用聲明為 final,但是必須不可被后面的代碼修改(即隱性的具有 final 的語(yǔ)義)

int num = 1;  
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;  
//報(bào)錯(cuò)信息:Local variable num defined in an enclosing scope must be final or effectively 
 final

在 Lambda 表達(dá)式當(dāng)中不允許聲明一個(gè)與局部變量同名的參數(shù)或者局部變量。

String first = "";  
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //編譯會(huì)出錯(cuò) 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Lambda是java8出的新特性,之前很少用Lambda表達(dá)式寫代碼,現(xiàn)在慢慢習(xí)慣用Lambda表達(dá)式,并且記得...
    安仔夏天勤奮閱讀 528評(píng)論 0 1
  • 注:之前關(guān)于Java8的認(rèn)知一直停留在知道有哪些修改和新的API上,對(duì)Lambda的認(rèn)識(shí)也是僅僅限于對(duì)匿名內(nèi)部類的...
    mualex閱讀 2,927評(píng)論 1 4
  • Java8-Lambda Java 8 的最大變化是引入了 Lambda 表達(dá)式——一種緊湊的、傳遞行為的方式 引...
    Cool_Pomelo閱讀 421評(píng)論 0 5
  • 原文鏈接: Lambdas 原文作者: shekhargulati 譯者: leege100 lambda表達(dá)式是...
    忽來(lái)閱讀 6,745評(píng)論 8 129
  • 自人類社會(huì)誕生以來(lái),財(cái)富的形式也在不斷的改變和進(jìn)化。最初的人類生活只能滿足于生存,因而財(cái)富的形式是各種能讓人們活下...
    康斯坦丁tony閱讀 899評(píng)論 0 0

友情鏈接更多精彩內(nèi)容