Java Lambda表達(dá)式詳解
Java Lambda表達(dá)式是JDK8引入的,是一個(gè)比較重要的特性
Lambda表達(dá)式簡(jiǎn)介
Lambda 表達(dá)式是 JDK8 的一個(gè)新特性,也被稱為閉包,Lambda表達(dá)式允許把函數(shù)作為一個(gè)方法的參數(shù),即行為參數(shù)化,函數(shù)作為參數(shù)傳遞進(jìn)方法中。
Lambda表達(dá)式可以取代大部分的匿名內(nèi)部類,寫(xiě)出更優(yōu)雅的 Java 代碼,尤其在集合的遍歷和其他集合操作中,可以極大地優(yōu)化代碼結(jié)構(gòu)。
Lambda表達(dá)式的作用
Java 8 引入的 Lambda表達(dá)式的主要作用就是簡(jiǎn)化代碼,寫(xiě)出更優(yōu)雅的代碼。
怎么一個(gè)簡(jiǎn)化優(yōu)雅呢,舉一Lambda語(yǔ)法創(chuàng)建線程和匿名內(nèi)部類創(chuàng)建線程的例子,就非常清楚了。
1.匿名類創(chuàng)建線程
// JDK7匿名內(nèi)部類寫(xiě)法 new Thread(new Runnable() {//接口名 ????????@Override ????????public void run() {//方法名 ????????????System.out.println("mikechen"); ????????} ????});
2.Lambda表達(dá)式創(chuàng)建線程
// JDK8 Lambda來(lái)創(chuàng)建線程 new Thread(() -> System.out.println("mikechen"));
上述代碼跟匿名內(nèi)部類的作用是一樣的,但比匿名內(nèi)部類更進(jìn)一步,這里連接口名和函數(shù)名都一同省掉了,Lambda表達(dá)式可以取代匿名內(nèi)部類,寫(xiě)出更優(yōu)雅的代碼。
Lambda表達(dá)式的語(yǔ)法
lambda 表達(dá)式的語(yǔ)法格式如下:
- ():左側(cè)部分指定了Lambda表達(dá)式需要的所有參數(shù)。
- ->:Lambda表達(dá)式的操作符或者箭頭操作符。
- {}:右側(cè)部分指定了Lambda體,即方法需要實(shí)現(xiàn)的內(nèi)容。
1.無(wú)參數(shù)
Lambda體只有一條語(yǔ)句:
示例:
()?->?System.out.println("mikechen");
請(qǐng)注意,括號(hào)中沒(méi)有內(nèi)容。那就是表示lambda不帶任何參數(shù)。
2.一個(gè)參數(shù)
示例:
Consumer<String> con = (x) -> System.out.println(x);
當(dāng)lambda表達(dá)式是單個(gè)參數(shù)時(shí),也可以省略括號(hào),如下所示:
Consumer<String> con = x -> System.out.println(x);
3.多個(gè)參數(shù)
如果Java lambda表達(dá)式匹配的方法有多個(gè)參數(shù),則需要在括號(hào)內(nèi)列出這些參數(shù),代碼如下:
BinaryOperator<Integer> bo = (a, b) -> { System.out.println("函數(shù)式接口"); return a + b; };
注意:僅當(dāng)方法是單個(gè)參數(shù)時(shí),才可以省略括號(hào)。
4.指定參數(shù)類型
如果編譯器無(wú)法從lambda匹配的函數(shù)式接口抽象方法推斷參數(shù)類型,則有時(shí)可能需要為lambda表達(dá)式指定參數(shù)類型。
(Car car) -> System.out.println("The car is: " + car.getName());
如你所見(jiàn),car參數(shù)的類型(Car)寫(xiě)在參數(shù)名稱的前面,就像在其他方法中聲明參數(shù)或?qū)涌谶M(jìn)行匿名實(shí)現(xiàn)時(shí)一樣。
5.只有一條語(yǔ)句時(shí)
當(dāng)Lambda體只有一條語(yǔ)句時(shí),return和大括號(hào)可以省略,示例:
BinaryOperator<Integer> bo = (a, b) -> a + b;
6.參數(shù)類型不寫(xiě)
Lambda表達(dá)式的參數(shù)列表的數(shù)據(jù)類型可以省略不寫(xiě),因?yàn)镴VM編譯器能夠通過(guò)上下文推斷出數(shù)據(jù)類型,這就是“類型推斷”,示例:
BinaryOperator<Integer> bo = (Integer a, Integer b) -> { return a + b; };
等同于
BinaryOperator<Integer> bo = (a, b) -> { return a + b; };
上述 Lambda 表達(dá)式中的參數(shù)類型都是由編譯器推斷得出,Lambda 表達(dá)式中無(wú)需指定類型,程序依然可以編譯,這是因?yàn)?javac 根據(jù)程序的上下文,在后臺(tái)推斷出了參數(shù)的類型。
Lambda 表達(dá)式的類型依賴于上下文環(huán)境,是由編譯器推斷出來(lái)的,這就是所謂的“類型推斷”。
7.Lambda表達(dá)式返回值
你可以從Java lambda表達(dá)式返回值,就像從方法中返回值一樣。你只需向lambda表達(dá)式主體添加一個(gè)return,如下所示:
(param) -> { System.out.println("param: " + param); return "return value"; }
函數(shù)式接口
Lambda表達(dá)式需要函數(shù)式接口的支持,所以,我們有必要來(lái)說(shuō)說(shuō)什么是函數(shù)式接口。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {}
一種用于表示一個(gè)接口是Java語(yǔ)言規(guī)范定義的函數(shù)式接口的注解類型。
對(duì)于函數(shù)式接口,我們可以理解為只有一個(gè)抽象方法的接口,除此之外它和別的接口相比并沒(méi)有什么特殊的地方。
public interface MyFunctionInterface<T> { public T getValue(T t); }
為了確保函數(shù)式接口的正確性,我們可以給這個(gè)接口添加@FunctionalInterface注解,這樣當(dāng)其中有超過(guò)一個(gè)抽象方法時(shí)就會(huì)報(bào)錯(cuò)。
Unexpected @FunctionalInterface annotation @FunctionalInterface ^ WorkerInterface is not a functional interface multiple non-overriding abstract methods found in interface WorkerInterface 1 error
Java 8中每一個(gè)Lambda表達(dá)式必須有一個(gè)函數(shù)式接口與之對(duì)應(yīng),也就是說(shuō),只要一個(gè)對(duì)象是函數(shù)式接口的實(shí)例,那么該對(duì)象就可以用Lambda表達(dá)式來(lái)表示。
Lambda表達(dá)式的舉例
學(xué)習(xí) Lambda 表達(dá)式的最好方式是學(xué)習(xí)例子,下面我們看幾個(gè)比較常用的例子。
1.lambda創(chuàng)建線程
使用() -> {} 替代匿名類:
//JDK 8之前 new Thread(new Runnable() { @Override public void run() { System.out.println("使用匿名內(nèi)部類,開(kāi)線程"); } }).start(); //JDK 8 使用lambda表達(dá)式 new Thread(() -> System.out.println("使用lambda表達(dá)式,開(kāi)線程")).start();
2.lambda事件處理
使用lambda表達(dá)式如下所示寫(xiě)出更好的事件偵聽(tīng)器的代碼:
// Java 8之前: button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button被點(diǎn)擊了使用老的方式!"); } }); // Java 8方式: button.addActionListener( (e) -> { System.out.println("Button被點(diǎn)擊了使用Lambda表達(dá)式!"); });
3.lambda遍歷List集合
集合的遍歷,采用lambda表達(dá)式會(huì)更簡(jiǎn)潔:
// Java 8之前: List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); for (String feature : features) { System.out.println(feature); } // Java 8之后: List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); features.forEach(n -> System.out.println(n)); // 使用Java 8的方法引用更方便,方法引用由::雙冒號(hào)操作符標(biāo)示, features.forEach(System.out::println);
方法引用是使用兩個(gè)冒號(hào)::這個(gè)操作符號(hào)。
4.元素排序
之前我們?nèi)粢獮榧蟽?nèi)的元素排序,就必須調(diào)用 sort 方法,傳入比較器重寫(xiě) compare。
方法的比較器對(duì)象,現(xiàn)在我們還可以使用 lambda 表達(dá)式來(lái)簡(jiǎn)化代碼。
public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("d"); list.add("b"); list.add("c"); list.sort((o1,o2)->o1.compareTo(o2)); list.forEach(System.out::println); }
5.lambda Map
// 不使用lambda表達(dá)式為每個(gè)訂單加上12%的稅 List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); for (Integer cost : costBeforeTax) { double price = cost + .12*cost; System.out.println(price); } // 使用lambda表達(dá)式 List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);
6.lambda過(guò)濾String
// 創(chuàng)建一個(gè)字符串列表,每個(gè)字符串長(zhǎng)度大于2 List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList()); System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);
7.lambda對(duì)集合應(yīng)用函數(shù)
// 將字符串換成大寫(xiě)并用逗號(hào)鏈接起來(lái) List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada"); String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", ")); System.out.println(G7Countries);
8.lambda計(jì)算最大值、最小值、平均值
//獲取數(shù)字的個(gè)數(shù)、最小值、最大值、總和以及平均值 List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29); IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("Highest prime number in List : " + stats.getMax()); System.out.println("Lowest prime number in List : " + stats.getMin()); System.out.println("Sum of all prime numbers : " + stats.getSum()); System.out.println("Average of all prime numbers : " + stats.getAverage());
以上就是Java Lambda表達(dá)式詳解的詳細(xì)內(nèi)容,更多關(guān)于Java Lambda表達(dá)式詳解的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Redis 集成Spring的示例代碼(spring-data-redis)
本篇文章主要介紹了Redis 集成Spring的示例代碼(spring-data-redis) ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09解決idea每次新建項(xiàng)目都需要重新指定maven目錄
這篇文章主要介紹了解決idea每次新建項(xiàng)目都需要配置maven,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09詳解Java中的延時(shí)隊(duì)列 DelayQueue
這篇文章主要介紹了Java中延時(shí)隊(duì)列 DelayQueue的相關(guān)資料,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼
本篇文章主要介紹了mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04Spring導(dǎo)入properties配置文件代碼示例
這篇文章主要介紹了Spring導(dǎo)入properties配置文件代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10