java8中的lambda表達(dá)式簡(jiǎn)介
Lambda表達(dá)式類似匿名函數(shù),簡(jiǎn)單地說(shuō),它是沒(méi)有聲明的方法,也即沒(méi)有訪問(wèn)修飾符、返回值聲明和方法名。
Lambda允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)。
Lambda表達(dá)式的語(yǔ)法
(parameters) -> expression
或
(parameters) -> { statements; }參數(shù)說(shuō)明:
- 可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識(shí)別參數(shù)值。
- 可選的參數(shù)圓括號(hào):一個(gè)參數(shù)無(wú)需定義圓括號(hào),但多個(gè)參數(shù)需要定義圓括號(hào)。
- 可選的大括號(hào):如果主體包含了一個(gè)語(yǔ)句,就不需要使用大括號(hào)。
- 可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會(huì)自動(dòng)返回值,大括號(hào)需要指明表達(dá)式返回了一個(gè)數(shù)值。
舉例說(shuō)明:
// 1. 不需要參數(shù),返回值為5 () -> 5 // 2. 接收一個(gè)參數(shù)(數(shù)字類型),返回其2倍的值 x -> 2 * x // 3. 接受2個(gè)參數(shù)(數(shù)字),并返回他們的差值 (x, y) -> x – y // 4. 接收2個(gè)int型整數(shù),返回他們的和 (int x, int y) -> x + y // 5. 接受一個(gè) string 對(duì)象,并在控制臺(tái)打印,不返回任何值(看起來(lái)像是返回void) (String s) -> System.out.print(s)
Lambda表達(dá)式作用域
lambda表達(dá)式中可以引用任何外部的變量或者常量。但是對(duì)這些外部的變量是有要求的:它們必須是Effectively final的。
局部?jī)?nèi)部類和匿名內(nèi)部類訪問(wèn)的局部變量必須由final修飾,java8開始,可以不加final修飾符,由系統(tǒng)默認(rèn)添加。java將這個(gè)功能稱為:Effectively final功能。
方法引用
指向靜態(tài)方法的方法引用
Function<String, Integer> function1 = Integer::parseInt; // 等價(jià)于下面 Function<String, Integer> function2 = (String i) -> Integer.parseInt(i);
指向任意類型實(shí)例方法的方法引用
Function<String, String> function3 = String::toLowerCase; // 等價(jià)于下面 Function<String, String> function4 = (String i) -> i.toLowerCase(); BiFunction<String, Integer, String> biFunction = (String s, Integer i) -> s.substring(i); BiFunction<String, Integer, String> biFunction2 = String::substring;
指向現(xiàn)有對(duì)象的實(shí)例方法的方法引用
String str = "hello"; Supplier<Integer> supplier = () -> str.length(); Supplier<Integer> supplier2 = str::length; Function<Integer, String> function5 = (Integer i) -> str.substring(i); Function<Integer, String> function6 = str::substring;
構(gòu)造方法引用
package com.morris.java8.lamdba;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
public class MethodReferenceExample {
public static void main(String[] args) {
// 構(gòu)造函數(shù)引用
Supplier<String> stringSupplier = () -> new String();
Supplier<String> stringSupplier2 = String::new;
Function<String, String> stringFunction = (String s)->new String(s);
Function<String, String> stringFunction2 = String::new;
BiFunction<Runnable, String, Thread> stringBiFunction = (Runnable r, String b)-> new Thread(r, b);
BiFunction<Runnable, String, Thread> stringBiFunction2 = Thread::new;
ThreeFunction<ThreadGroup, Runnable, String, Thread> threeFunction = (ThreadGroup g, Runnable r, String b)-> new Thread(g, r, b);
ThreeFunction<ThreadGroup, Runnable, String, Thread> threeFunction2 = Thread::new;
}
interface ThreeFunction<A, B, C, D> {
D triple(A a, B b, C c);
}
}
lambda與匿名內(nèi)部類
從表面上看到Lambda表達(dá)式似乎只是為了簡(jiǎn)化匿名內(nèi)部類書寫,這看起來(lái)僅僅通過(guò)語(yǔ)法糖在編譯階段把所有的Lambda表達(dá)式替換成匿名內(nèi)部類就可以了。但實(shí)際并非如此。在JVM層面,Lambda表達(dá)式和匿名內(nèi)部類有著明顯的差別。
匿名內(nèi)部類
匿名內(nèi)部類仍然是一個(gè)類,只是不需要程序員顯示指定類名,編譯器會(huì)自動(dòng)為該類取名。
public class AnonymousClassDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("this is an Anonymous class demo");
}
});
}
}
因此上面的代碼,編譯之后將會(huì)產(chǎn)生兩個(gè)class文件:
AnonymousClassDemo.class AnonymousClassDemo$1.class
進(jìn)一步分析主類AnonymousClassDemo.class的字節(jié)碼,可發(fā)現(xiàn)其創(chuàng)建了匿名內(nèi)部類的對(duì)象:
$ javap -v -p AnonymousClassDemo.class
...
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=1, args_size=1
0: new #2 // class java/lang/Thread
3: dup
4: new #3 // class AnonymousClassDemo$1 創(chuàng)建匿名內(nèi)部類
7: dup
8: invokespecial #4 // Method AnonymousClassDemo$1."<init>":()V
11: invokespecial #5 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
14: pop
15: return
LineNumberTable:
line 5: 0
line 11: 15
}
SourceFile: "AnonymousClassDemo.java"
InnerClasses:
static #3; //class AnonymousClassDemo$1lambda表達(dá)式
Lambda表達(dá)式通過(guò)invokedynamic指令實(shí)現(xiàn),不會(huì)產(chǎn)生新的類。
public class LambdaDemo {
public static void main(String[] args) {
new Thread(()-> System.out.println("this is a lambda demo"));
}
}上面的代碼編譯之后只有一個(gè)class文件:
LambdaDemo.class
通過(guò)javap查看LambdaDemo.class的字節(jié)碼,我們更能看出Lambda表達(dá)式內(nèi)部表示的不同。
$ javap -v -p LambdaDemo.class
...
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: new #2 // class java/lang/Thread
3: dup
4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable; 使用invokedynamic指令調(diào)用
9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: pop
13: return
LineNumberTable:
line 4: 0
line 5: 13
private static void lambda$main$0(); // Lambda表達(dá)式被封裝成主類的私有方法
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #6 // String this is a lambda demo
5: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 4: 0
}
SourceFile: "LambdaDemo.java"
InnerClasses:
public static final #51= #50 of #54; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #22 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#23 ()V
#24 invokestatic LambdaDemo.lambda$main$0:()V
#23 ()V
反編譯之后我們發(fā)現(xiàn)Lambda表達(dá)式被封裝成了主類的一個(gè)私有方法,并通過(guò)invokedynamic指令進(jìn)行調(diào)用。
既然Lambda表達(dá)式不是內(nèi)部類的簡(jiǎn)寫,那么Lambda內(nèi)部的this引用也就跟內(nèi)部類對(duì)象沒(méi)什么關(guān)系了。在Lambda表達(dá)式中this的意義跟在表達(dá)式外部完全一樣。
總結(jié)
相同點(diǎn):
- 都可以直接訪問(wèn)“effectively final”的局部變量(不需要加final關(guān)鍵字,但實(shí)際上是final,編譯器編譯時(shí)會(huì)自動(dòng)加上),以及外部類的成員變量(包括實(shí)例變量和類變量)。
不同點(diǎn):
- 匿名內(nèi)部類可以為任意接口創(chuàng)建實(shí)例——不管接口包含多少個(gè)抽象方法,只要匿名內(nèi)部類實(shí)現(xiàn)所有的抽象方法即可。但Lambda表達(dá)式只能為函數(shù)式接口創(chuàng)建實(shí)例。
- 匿名內(nèi)部類可以為抽象類、甚至普通類創(chuàng)建實(shí)例,但Lambda表達(dá)式只能為函數(shù)式接口創(chuàng)建實(shí)例。
- 匿名內(nèi)部類實(shí)現(xiàn)的抽象方法的方法體允許調(diào)用接口中定義的默認(rèn)方法;但Lambda表達(dá)式的代碼塊不允許調(diào)用接口中定義的默認(rèn)方法。
到此這篇關(guān)于java8 lambda表達(dá)式簡(jiǎn)介的文章就介紹到這了,更多相關(guān)java8 lambda表達(dá)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 一文帶你看懂Java8中的lambda表達(dá)式和方法引用
- Java8新特性-Lambda表達(dá)式詳解
- java8新特性-lambda表達(dá)式入門學(xué)習(xí)心得
- Java8?lambda表達(dá)式的10個(gè)實(shí)例講解
- 詳解Java8如何使用Lambda表達(dá)式進(jìn)行比較
- Java8新特性:lambda表達(dá)式總結(jié)
- java8 forEach結(jié)合Lambda表達(dá)式遍歷 List操作
- Java8 用Lambda表達(dá)式給List集合排序的實(shí)現(xiàn)
- Java8中的Lambda表達(dá)式理解與使用示例詳解
相關(guān)文章
Java去重排序之Comparable與Comparator的使用及說(shuō)明
這篇文章主要介紹了Java去重排序之Comparable與Comparator的使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
SpringBoot實(shí)現(xiàn)統(tǒng)一功能處理的教程詳解
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)統(tǒng)一功能處理,文中的示例代碼講解詳細(xì),對(duì)大家學(xué)習(xí)或工作有一定借鑒價(jià)值,感興趣的同學(xué)可以參考閱讀下2023-05-05
java利用mybatis攔截器統(tǒng)計(jì)sql執(zhí)行時(shí)間示例
這篇文章主要介紹了java利用mybatis攔截器統(tǒng)計(jì)sql執(zhí)行時(shí)間示例,該攔截器攔截mybatis的query和update操作,能統(tǒng)計(jì)sql執(zhí)行時(shí)間2014-03-03
Graceful Response 構(gòu)建 Spring Boot 響應(yīng)
Graceful Response是一個(gè)Spring Boot技術(shù)棧下的優(yōu)雅響應(yīng)處理器,提供一站式統(tǒng)一返回值封裝、全局異常處理、自定義異常錯(cuò)誤碼等功能,本文介紹Graceful Response 構(gòu)建 Spring Boot 下優(yōu)雅的響應(yīng)處理,感興趣的朋友一起看看吧2024-01-01
SpringBoot集成Quartz實(shí)現(xiàn)持久化定時(shí)接口調(diào)用任務(wù)
Quartz是功能強(qiáng)大的開源作業(yè)調(diào)度庫(kù),幾乎可以集成到任何?Java?應(yīng)用程序中,從最小的獨(dú)立應(yīng)用程序到最大的電子商務(wù)系統(tǒng),本文將通過(guò)代碼示例給大家介紹SpringBoot集成Quartz實(shí)現(xiàn)持久化定時(shí)接口調(diào)用任務(wù),需要的朋友可以參考下2023-07-07
Java中Request請(qǐng)求轉(zhuǎn)發(fā)詳解
這篇文章主要介紹了Java中Request請(qǐng)求轉(zhuǎn)發(fā)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
SpringBoot的WebSocket實(shí)現(xiàn)單聊群聊
這篇文章主要為大家詳細(xì)介紹了SpringBoot的WebSocket實(shí)現(xiàn)單聊群聊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-02-02

