Java函數(shù)接口和Lambda表達(dá)式深入分析
一、函數(shù)接口
函數(shù)接口是一個(gè)具有單個(gè)抽象方法的接口,接口設(shè)計(jì)主要是為了支持 Lambda 表達(dá)式和方法引用,使得 Java 能更方便地實(shí)現(xiàn)函數(shù)式編程風(fēng)格。
特點(diǎn)和用途:
- 單一抽象方法: 函數(shù)接口只能有
一個(gè)
抽象方法,但可以有多個(gè)
默認(rèn)方法(default)或靜態(tài)方法(static)。 - Lambda 表達(dá)式: 可以使用函數(shù)接口創(chuàng)建 Lambda 表達(dá)式,從而簡潔地表示匿名函數(shù),例如在集合操作、線程處理等場景中。
- 方法引用: 可以通過函數(shù)接口的類型來引用一個(gè)已存在的方法,使代碼更簡潔和可讀性更高。
Java 8 提供了幾個(gè)標(biāo)準(zhǔn)的函數(shù)接口,接口通常位于 java.util.function
包中。
常見的函數(shù)接口:
Consumer: 接收一個(gè)輸入?yún)?shù)并且不返回結(jié)果的操作。
Consumer<String> printConsumer = str -> System.out.println(str); printConsumer.accept("Hello World!");
Supplier: 不接收參數(shù)但是返回結(jié)果的提供型接口。
Supplier<Double> randomSupplier = () -> Math.random(); System.out.println(randomSupplier.get());
Function: 接收一個(gè)輸入?yún)?shù),并返回結(jié)果。
Function<Integer, String> intToString = num -> String.valueOf(num); System.out.println(intToString.apply(123));
Predicate: 接收一個(gè)輸入?yún)?shù),并返回一個(gè)布爾值結(jié)果。
Predicate<Integer> isEven = num -> num % 2 == 0; System.out.println(isEven.test(5)); // false
UnaryOperator: 繼承自 Function<T, T>,表示一元操作符。
UnaryOperator<Integer> square = num -> num * num; System.out.println(square.apply(5)); // 25
自定義函數(shù)接口:只需確保接口中只有一個(gè)抽象方法即可。
@FunctionalInterface interface MyFunctionalInterface { void myMethod(); // 允許有默認(rèn)方法和靜態(tài)方法 default void anotherMethod() { System.out.println("Default method"); } } // 使用自定義的函數(shù)接口 MyFunctionalInterface myFunc = () -> System.out.println("Hello Custom Functional Interface"); myFunc.myMethod(); myFunc.anotherMethod();
二、Lambda表達(dá)式簡介
Lambda 表達(dá)式可以被視為匿名函數(shù)的一種聲明方式,允許將函數(shù)作為方法參數(shù)傳遞,或者在需要函數(shù)式接口的地方使用。
基本結(jié)構(gòu):
// parameters:參數(shù)列表,可以為空或非空
// ->:箭頭符號(hào),分隔參數(shù)列表和Lambda表達(dá)式的主體
// expression:單行表達(dá)式作為 Lambda 主體
(parameters) -> expression// { statements; }:代碼塊作為 Lambda 主體,可以包含多條語句和返回語句
(parameters) -> { statements; }
表達(dá)式的特點(diǎn):
- 簡潔性和可讀性: Lambda 表達(dá)式使代碼更為簡潔,尤其是在處理函數(shù)式接口時(shí),省去了冗余的語法。
- 函數(shù)式編程風(fēng)格: Lambda 表達(dá)式支持函數(shù)式編程,可以輕松地進(jìn)行函數(shù)傳遞、方法引用和流式操作等。
- 閉包性: Lambda 表達(dá)式可以捕獲其周圍的變量,使得函數(shù)式編程中的狀態(tài)管理更加靈活。
案例:通過 Lambda 表達(dá)式為 MathOperation
接口的 operation
方法提供了四種不同的實(shí)現(xiàn):加法、減法、乘法和除法。
接口的定義:
interface MathOperation { int operation(int a, int b); }
使用 Lambda 表達(dá)式來實(shí)現(xiàn)這個(gè)接口,以便傳遞不同的數(shù)學(xué)運(yùn)算邏輯:
public class LambdaDemo { public static void main(String[] args) { // Lambda 表達(dá)式實(shí)現(xiàn)加法 MathOperation addition = (int a, int b) -> a + b; System.out.println("10 + 5 = " + operate(10, 5, addition)); // Lambda 表達(dá)式實(shí)現(xiàn)減法 MathOperation subtraction = (a, b) -> a - b; System.out.println("10 - 5 = " + operate(10, 5, subtraction)); // Lambda 表達(dá)式實(shí)現(xiàn)乘法 MathOperation multiplication = (int a, int b) -> { return a * b; }; System.out.println("10 * 5 = " + operate(10, 5, multiplication)); // Lambda 表達(dá)式實(shí)現(xiàn)除法 MathOperation division = (a, b) -> a / b; System.out.println("10 / 5 = " + operate(10, 5, division)); } private static int operate(int a, int b, MathOperation mathOperation) { return mathOperation.operation(a, b); } }
三、Lambda表達(dá)式外部參數(shù)
Lambda 表達(dá)式有自己特定的作用域規(guī)則,可以捕獲和訪問其周圍的變量, 可以隨意引用外部變量,但如果外部變量是在當(dāng)前作用域聲明的,則一定不可以進(jìn)行第二次賦值,哪怕是在 lambda 語句之后。
局部變量:Lambda 表達(dá)式可以訪問它們所在方法的局部變量,但是這些變量必須是隱式最終或?qū)嶋H上是最終的(final
)。這意味著變量一旦賦值后不再改變。Lambda 表達(dá)式內(nèi)部不允許修改這些局部變量的值,否則編譯器會(huì)報(bào)錯(cuò)。
public class LambdaScopeDemo { public static void main(String[] args) { int num = 10; // 局部變量 MathOperation addition = (int a, int b) -> { // num = 5; // 錯(cuò)誤!Lambda 表達(dá)式不能修改局部變量的值 // 這里訪問了局部變量 num return a + b + num; }; System.out.println(addition.operation(5, 3)); } }
字段:Lambda 表達(dá)式可以訪問外部類的字段(成員變量),包括實(shí)例字段和靜態(tài)字段。
public class LambdaScopeDemo { private static int staticNum; // 靜態(tài)字段 private int instanceNum; // 實(shí)例字段 public void testLambdaScope() { MathOperation addition = (int a, int b) -> { // 訪問實(shí)例字段和靜態(tài)字段 int result = a + b + instanceNum + staticNum; return result; }; System.out.println(addition.operation(5, 3)); } }
接口的默認(rèn)方法:Lambda 表達(dá)式可以訪問接口中定義的默認(rèn)方法,但不能訪問接口中定義的實(shí)例字段。
四、Lambda范例
使用Lambda表達(dá)式時(shí),常見的場景包括對集合的遍歷、排序、過濾以及與函數(shù)式接口的結(jié)合使用。
常見的Java 8 Lambda表達(dá)式示例:
遍歷集合
public static void main(String[] args) { List<String> names = new ArrayList<>(); names.add("Alice"); names.add("Bob"); names.add("Charlie"); // 使用 Lambda 表達(dá)式遍歷集合 names.forEach(name -> System.out.println(name)); }
使用函數(shù)式接口進(jìn)行計(jì)算
參考:二、Lambda表達(dá)式簡介
使用函數(shù)式接口進(jìn)行條件過濾
public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // 使用 Lambda 表達(dá)式過濾偶數(shù) System.out.println("偶數(shù):"); filter(numbers, n -> n % 2 == 0); // 使用 Lambda 表達(dá)式過濾大于 5 的數(shù) System.out.println("大于 5 的數(shù):"); filter(numbers, n -> n > 5); } private static void filter(List<Integer> numbers, Predicate<Integer> condition) { for (Integer number : numbers) { if (condition.test(number)) { System.out.print(number + " "); } } System.out.println(); }
使用Comparator進(jìn)行集合排序
public static void main(String[] args) { List<String> names = new ArrayList<>(); names.add("Alice"); names.add("Bob"); names.add("Charlie"); // 使用 Lambda 表達(dá)式進(jìn)行排序(根據(jù)字符串長度) names.sort((s1, s2) -> s1.length() - s2.length()); // 輸出排序后的結(jié)果 names.forEach(name -> System.out.println(name)); }
使用 Runnable 執(zhí)行代碼塊
參考:五、Runnable Lambda表達(dá)式
五、Runnable Lambda表達(dá)式
使用 Lambda 表達(dá)式來簡潔地實(shí)現(xiàn) Runnable
接口的實(shí)例化。Runnable
接口是一個(gè)函數(shù)接口,它只包含一個(gè)抽象方法 void run()
,用于定義一個(gè)可以由線程執(zhí)行的任務(wù)。
匿名內(nèi)部類(Java 7 及之前):
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Running in a separate thread"); } }; Thread thread = new Thread(runnable); thread.start();
Lambda 表達(dá)式(Java 8+):
Runnable runnable = () -> { System.out.println("Running in a separate thread"); }; Thread thread = new Thread(runnable); thread.start();
更簡潔的方式:任務(wù)非常簡單,可以進(jìn)一步簡化,直接將 Lambda 表達(dá)式作為參數(shù)傳遞給 Thread
的構(gòu)造函數(shù):
Thread thread = new Thread(() -> { System.out.println("Running in a separate thread"); }); thread.start();
這種方式避免了顯式地聲明 Runnable
變量,使代碼更加緊湊和易讀。
案例:
public static void main(String[] args) { // 使用 Lambda 表達(dá)式創(chuàng)建一個(gè)新的線程 Thread thread = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("線程執(zhí)行:" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); // 啟動(dòng)線程 thread.start(); }
以上就是Java函數(shù)接口和Lambda表達(dá)式深入分析的詳細(xì)內(nèi)容,更多關(guān)于Java函數(shù)接口的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
scala+redis實(shí)現(xiàn)分布式鎖的示例代碼
這篇文章主要介紹了scala+redis實(shí)現(xiàn)分布式鎖的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06springboot-curd基于mybatis項(xiàng)目搭建
這篇文章主要介紹了springboot-curd基于mybatis項(xiàng)目搭建,圍繞相關(guān)資料展開詳細(xì)內(nèi)容,希望對正在學(xué)習(xí)的你有所幫助,需要的小伙伴也可以參考一下2022-01-01Spring?Security權(quán)限注解啟動(dòng)及邏輯處理使用示例
這篇文章主要為大家介紹了Spring?Security權(quán)限注解啟動(dòng)及邏輯處理使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07spring?cloud?eureka注冊原理-注冊失敗填坑筆記
這篇文章主要介紹了spring?cloud?eureka注冊原理-注冊失敗填坑筆記,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Java ProcessBuilder執(zhí)行多次CMD命令的使用
本文介紹了Java的ProcessBuilder類,該類用于執(zhí)行外部命令,通過ProcessBuilder,我們可以在Java程序中靈活地執(zhí)行多次CMD命令,并控制輸入輸出流以及工作目錄等,感興趣的可以了解一下2024-11-11解決Spring boot 嵌入的tomcat不啟動(dòng)問題
這篇文章主要介紹了解決Spring boot 嵌入的tomcat不啟動(dòng)問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10spring boot @ResponseBody轉(zhuǎn)換JSON 時(shí) Date 類型處理方法【兩種方法】
這篇文章主要介紹了spring boot @ResponseBody轉(zhuǎn)換JSON 時(shí) Date 類型處理方法,主要給大家介紹Jackson和FastJson兩種方式,每一種方法給大家介紹的都非常詳細(xì),需要的朋友可以參考下2018-08-08