深入理解Java8新特性之Lambda表達(dá)式的基本語法和自定義函數(shù)式接口
1.寫在前面
目前我們學(xué)習(xí)Java主要用到的應(yīng)該就是Java8了,或者說大部分企業(yè)當(dāng)前使用的也是Java8。那么既然Java8的應(yīng)用如此之廣泛,一定有一些亮點(diǎn)所在:
- Lambda 表達(dá)式
- 函數(shù)式接口
- 方法引用與構(gòu)造器引用
- Stream API
- 接口中的默認(rèn)方法與靜態(tài)方法
- 新時(shí)間日期API
- 其他新特性
速度更快、代碼更少(增加了新的語法 Lambda 表達(dá)式)、強(qiáng)大的 Stream API、便于并行、最大化減少空指針異常 Optional。
2.為什么要使用Lambda表達(dá)式?
Lambda 是一個(gè) 匿名函數(shù) 數(shù),我們可以把 Lambda表達(dá)式理解為是 一段可以傳遞的 代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞)??梢詫懗龈?jiǎn)潔、更靈活的代碼。作為一種更緊湊的代碼風(fēng)格,使Java語言表達(dá)能力得到了提升。
3.Lambda表達(dá)式的基本語法
Lambda 表達(dá)式在Java 語言中引入了一個(gè)新的語法元素和操作符。這個(gè)操作符為 “ -> ” , 該操作符被稱為 Lambda 操作符或剪頭操作符。
它將 Lambda 分為兩個(gè)部分:
- 左側(cè) :指定了 Lambda 表達(dá)式需要的所有參數(shù)。
- 右側(cè) :指定了 Lambda 體,即 Lambda 表達(dá)式要執(zhí)行的功能。
具體的就看下面的代碼案例。
package com.szh.java8; import org.junit.Test; import java.util.Comparator; import java.util.function.Consumer; /** * Lambda 表達(dá)式的基礎(chǔ)語法: * Java8中引入了一個(gè)新的操作符 "->" * 該操作符稱為 箭頭操作符 或 Lambda操作符 * 箭頭操作符將 Lambda 表達(dá)式拆分成兩部分: * * 左側(cè):Lambda 表達(dá)式的參數(shù)列表 * 右側(cè):Lambda 表達(dá)式中所需執(zhí)行的功能, 即 Lambda 體 * * Lambda 表達(dá)式需要“函數(shù)式接口”的支持 * 函數(shù)式接口:接口中只有一個(gè)抽象方法的接口, 稱為函數(shù)式接口 * 可以使用注解 @FunctionalInterface 修飾, 可以檢查是否是函數(shù)式接口 */ public class MyTest2 { /** * 語法格式一:無參數(shù),無返回值 * () -> System.out.println("Hello World!!!"); */ @Test public void test1() { Runnable r1 = new Runnable() { @Override public void run() { System.out.println("Hello World!!!"); } }; r1.run(); System.out.println("---------------------------"); Runnable r2 = () -> System.out.println("Hello World!!!"); r2.run(); } }
package com.szh.java8; import org.junit.Test; import java.util.Comparator; import java.util.function.Consumer; /** * Lambda 表達(dá)式的基礎(chǔ)語法: * Java8中引入了一個(gè)新的操作符 "->" * 該操作符稱為 箭頭操作符 或 Lambda操作符 * 箭頭操作符將 Lambda 表達(dá)式拆分成兩部分: * * 左側(cè):Lambda 表達(dá)式的參數(shù)列表 * 右側(cè):Lambda 表達(dá)式中所需執(zhí)行的功能, 即 Lambda 體 * * Lambda 表達(dá)式需要“函數(shù)式接口”的支持 * 函數(shù)式接口:接口中只有一個(gè)抽象方法的接口, 稱為函數(shù)式接口 * 可以使用注解 @FunctionalInterface 修飾, 可以檢查是否是函數(shù)式接口 */ public class MyTest2 { /** * 語法格式二:有一個(gè)參數(shù),無返回值 * (x) -> System.out.println(x) * 此語法格式中小括號(hào)可以省略不寫,等價(jià)于 * x -> System.out.println(x) */ @Test public void test2() { Consumer<String> consumer = (str) -> System.out.println(str); consumer.accept("Lambda表達(dá)式真好用...."); } }
package com.szh.java8; import org.junit.Test; import java.util.Comparator; import java.util.function.Consumer; /** * Lambda 表達(dá)式的基礎(chǔ)語法: * Java8中引入了一個(gè)新的操作符 "->" * 該操作符稱為 箭頭操作符 或 Lambda操作符 * 箭頭操作符將 Lambda 表達(dá)式拆分成兩部分: * * 左側(cè):Lambda 表達(dá)式的參數(shù)列表 * 右側(cè):Lambda 表達(dá)式中所需執(zhí)行的功能, 即 Lambda 體 * * Lambda 表達(dá)式需要“函數(shù)式接口”的支持 * 函數(shù)式接口:接口中只有一個(gè)抽象方法的接口, 稱為函數(shù)式接口 * 可以使用注解 @FunctionalInterface 修飾, 可以檢查是否是函數(shù)式接口 */ public class MyTest2 { /** * 語法格式三:有兩個(gè)以上的參數(shù),有返回值,并且 Lambda 體中有多條語句 */ @Test public void test3() { Comparator<Integer> comparator = (x,y) -> { System.out.println("函數(shù)式接口...."); return Integer.compare(x,y); }; } }
package com.szh.java8; import org.junit.Test; import java.util.Comparator; import java.util.function.Consumer; /** * Lambda 表達(dá)式的基礎(chǔ)語法: * Java8中引入了一個(gè)新的操作符 "->" * 該操作符稱為 箭頭操作符 或 Lambda操作符 * 箭頭操作符將 Lambda 表達(dá)式拆分成兩部分: * * 左側(cè):Lambda 表達(dá)式的參數(shù)列表 * 右側(cè):Lambda 表達(dá)式中所需執(zhí)行的功能, 即 Lambda 體 * * Lambda 表達(dá)式需要“函數(shù)式接口”的支持 * 函數(shù)式接口:接口中只有一個(gè)抽象方法的接口, 稱為函數(shù)式接口 * 可以使用注解 @FunctionalInterface 修飾, 可以檢查是否是函數(shù)式接口 */ public class MyTest2 { /** * 語法格式四:若 Lambda 體中只有一條語句, * 則 return 和 大括號(hào)都可以省略不寫 * Lambda 表達(dá)式的參數(shù)列表的數(shù)據(jù)類型可以省略不寫, * 因?yàn)镴VM編譯器通過上下文推斷出,數(shù)據(jù)類型,即 “類型推斷” */ @Test public void test4() { Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y); } }
上述 Lambda 表達(dá)式中的參數(shù)類型都是由編譯器推斷得出的。Lambda 表達(dá)式中無需指定類型,程序依然可以編譯,這是因?yàn)?javac 根據(jù)程序的上下文,在后臺(tái)
推斷出了參數(shù)的類型。Lambda 表達(dá)式的類型依賴于上下文環(huán)境,是由編譯器推斷出來的。這就是所謂的 “類型推斷”。
4.自定義函數(shù)式接口
只包含一個(gè)抽象方法的接口,稱為 函 數(shù) 式 接 口。
你可以通過 Lambda 表達(dá)式來創(chuàng)建該接口的對(duì)象。(若 Lambda表達(dá)式拋出一個(gè)受檢異常,那么該異常需要在目標(biāo)接口的抽象方法上進(jìn)行聲明)
我們可以在任意函數(shù)式接口上使用 @FunctionalInterface 注解,這樣做可以檢查它是否是一個(gè)函數(shù)式接口,同時(shí) javadoc 也會(huì)包含一條聲明,說明這個(gè)接口是一個(gè)函數(shù)式接口。
就像Runnable接口一樣,它就是一個(gè)典型的函數(shù)式接口。
@FunctionalInterface public interface Runnable { /** * When an object implementing interface {@code Runnable} is used * to create a thread, starting the thread causes the object's * {@code run} method to be called in that separately executing * thread. * <p> * The general contract of the method {@code run} is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }
那么我們肯定也可以自定義函數(shù)式接口了,首先是沒有泛型的自定義函數(shù)式接口。
package com.szh.java8.two; /** * */ @FunctionalInterface public interface MyFunction { public String getValue(String str); }
package com.szh.java8.two; /** * */ public class TestLambda { private static String strHandler(String str,MyFunction mf) { return mf.getValue(str); } public static void main(String[] args) { //去除首尾空格 String trimStr = strHandler("\t\t\t 張起靈-小哥 ",(str) -> str.trim()); System.out.println(trimStr); //轉(zhuǎn)為大寫 String upperStr = strHandler("hello world",str -> str.toUpperCase()); System.out.println(upperStr); //部分截取 String newStr = strHandler("學(xué)Java的冷少",(str) -> str.substring(0,5)); System.out.println(newStr); } }
下面再來看一個(gè)帶泛型的函數(shù)式接口。
package com.szh.java8.three; /** * */ @FunctionalInterface public interface MyFunction2<T,R> { public R getValue(T t1,T t2); }
package com.szh.java8.three; import com.szh.java8.two.MyFunction; /** * */ public class TestLambda { private static void operation(Long l1,Long l2,MyFunction2<Long,Long> mf) { System.out.println(mf.getValue(l1,l2)); } public static void main(String[] args) { //和 operation(100L,200L,(x,y) -> x + y); //積 operation(300L,500L,(x,y) -> x * y); } }
作為參數(shù)傳遞 Lambda 表達(dá)式:為了將 Lambda 表達(dá)式作為參數(shù)傳遞 ,接收 Lambda 表達(dá)式的參數(shù)類型必須是與該 Lambda 表達(dá)式兼容的函數(shù)式接口的類型。
以上就是深入理解Java8新特性之Lambda表達(dá)式的基本語法和自定義函數(shù)式接口的詳細(xì)內(nèi)容,更多關(guān)于Java Lambda表達(dá)式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot中Formatter和Converter用法和區(qū)別小結(jié)
本文主要介紹了SpringBoot中Formatter和Converter用法和區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07IDEA項(xiàng)目maven?project沒有出現(xiàn)plugins和Dependencies問題
這篇文章主要介紹了IDEA項(xiàng)目maven?project沒有出現(xiàn)plugins和Dependencies問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12log4j如何根據(jù)變量動(dòng)態(tài)生成文件名
這篇文章主要介紹了log4j如何根據(jù)變量動(dòng)態(tài)生成文件名方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Spring自動(dòng)裝配之方法、構(gòu)造器位置的自動(dòng)注入操作
這篇文章主要介紹了Spring自動(dòng)裝配之方法、構(gòu)造器位置的自動(dòng)注入操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08springboot如何統(tǒng)一設(shè)置時(shí)區(qū)
這篇文章主要介紹了springboot如何統(tǒng)一設(shè)置時(shí)區(qū)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
這篇文章主要介紹了SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01Spring AOP 實(shí)現(xiàn)自定義注解的示例
這篇文章主要介紹了Spring AOP 實(shí)現(xiàn)自定義注解的示例,幫助大家更好的理解和學(xué)習(xí)使用spring框架,感興趣的朋友可以了解下2021-03-03