Lambda表達式(閉包):java8的新特性,lambda運行將函數作為一個方法的參數,也就是函數作為參數傳遞到方法中。使用lambda表達式可以讓程式碼更簡潔。
Lambda表達式的使用場景:用以簡化介面實作。
關於介面實現,可以有很多種方式來實現。例如:設計介面的實作類別、使用匿名內部類別。但是lambda表達式,比這兩種方式都簡單。
package test; /** * @author: Mercury * Date: 2022/3/20 * Time: 17:48 * Description:Lambda表达式 * Version:1.0 */ public class Test04 { public static void main(String[] args) { //使用lambda表达式实现接口 Test test = () -> { System.out.println("test"); }; test.test(); } } interface Test{ public void test(); }
雖然說,lambda表達式可以在⼀定程度上簡化介面的實作。但是,並不是所有的介面都可以使用lambda表達式來簡潔實現的。
lambda表達式畢竟只是⼀個匿名方法。當實作的介面中的方法過多或多少的時候,lambda表達式都是不適用的。
lambda表達式,只能實作函數式介面。
如果說,⼀個介面中,要求實作類別必須實作的抽象方法,有且只有⼀個!這樣的接口,就是函數式接口。
程式碼如下(範例):
//有且只有一个实现类必须要实现的抽象方法,所以是函数式接口 interface Test{ public void test(); }
是⼀個註解,用在介面之前,判斷這個介面是否是⼀個函數式介面。如果是函數式接口,沒有任何問題。如果不是函數式接口,則會報錯。功能類似於 @Override。
程式碼如下(範例):
@FunctionalInterface interface Test{ public void test(); }
lambda表達式,其實本質來講,就是⼀個匿名函數。因此在寫lambda表達式的時候,不需要關心方法名稱是什麼。
實際上,我們在寫lambda表達式的時候,也不需要關心回傳值型別。
我們在寫lambda表達式的時候,只需要關注兩部分內容即可:參數列表和方法體
lambda表達式的基礎語法:
(參數1,參數2,…) -> {
方法體
};
參數部分:方法的參數列表,要求和實現的介面中的方法參數部分⼀致,包括參數的數量和類型。
方法體部分 : 方法的實作部分,如果介面中定義的方法有回傳值,則在實作的時候,注意回傳值的回傳。
-> : 分隔參數部分和方法體部分。
程式碼範例:
package test; /** * @author: Mercury * Date: 2022/3/20 * Time: 17:48 * Description:Lambda表达式 * Version:1.0 */ public class Test04 { public static void main(String[] args) { //使用lambda表达式实现接口 //无参 // Test test = () -> { // System.out.println("test"); // }; //有参 // Test test = (name,age) -> { // System.out.println(name+age+"岁了!"); // }; // test.test("小新",18); //有参+返回值 Test test = (name,age) -> { System.out.println(name+age+"岁了!"); return age + 1; }; int age = test.test("小新",18); System.out.println(age); } } //无参 //interface Test{ // public void test(); //} //有参 无返回值 //interface Test{ // public void test(String name,int age); //} //有参 有返回值 interface Test{ public int test(String name,int age); }
參數部分的精簡
參數的類型
由於在介面的方法中,已經定義了每⼀個參數的型別是什麼。而且在使用lambda表達式實現介面的時候,必須確保參數的數量和類別 型需要和介面中的方法保持⼀致。因此,此時lambda表達式中的參數的型別可以省略不寫。
注意點:
如果需要省略參數的類型,要保證:要省略, 每⼀個參數的類型都必須省略不寫。絕對不能出現,有的參數型別省略了,有的參數型別沒有省略。
//有参+返回值 Test test = (name,age) -> { System.out.println(name+age+"岁了!"); return age + 1; }; int age = test.test("小新",18); System.out.println(age);
參數的小括號
如果方法的參數清單中的參數數量有且只有⼀個,此時,參數清單的小括號是可以省略不寫的。
注意事項:
只有當參數的數量是⼀個的時候, 多了、少了都不能省略。
省略掉小括號的同時,必須要省略參數的型別
//一个参数 Test test = name -> { System.out.println(name+"test"); }; test.test("小新");
方法體部分的精簡
方法體⼤括號的精簡
當⼀個方法體中的邏輯,有且只有⼀句的情況下,⼤括號可以省略
Test test = name -> System.out.println(name+"test"); test.test("小新");
return的精簡
如果⼀個方法中唯⼀的⼀條語句是⼀個回傳語句, 此時在省略掉大括號的同時, 也必須省略掉return。
Test test = (a,b) -> a+b;
lambda表達式是為了簡化介面的實作的。在lambda表達式中,不應該出現比較複雜的邏輯。過於複雜的邏輯在lambda表達式中的使用會大大影響程式的可讀性。通常情況下,如果lambda表達式需要處理複雜邏輯,我們會單獨寫一個方法來處理。在lambda表達式中直接引用這個方法即可。
函數引用:引用⼀個已經存在的方法,使其取代lambda表達式完成介面的實作
語法:類別::靜態方法
注意事項:
#在引用的方法後面,不要新增小括號。
引用的這個方法,參數(數量、型別)和回傳值,必須跟介面中定義的⼀致
package test; /** * @author: Mercury * Date: 2022/3/20 * Time: 18:17 * Description:lambda表达式静态方法引用 * Version:1.0 */ public class Test05 { public static void main(String[] args) { //实现多个参数,一个返回值的接口 //对一个静态方法的引用,语法:类::静态方法 Test1 test1 = Calculator::calculate; System.out.println(test1.test(4,5)); } } class Calculator{ public static int calculate(int a,int b ){ // 稍微复杂的逻辑:计算a和b的差值的绝对值 if (a > b) { return a - b; } return b - a; } } interface Test1{ int test(int a,int b); } package test; /** * @author: Mercury * Date: 2022/3/20 * Time: 18:17 * Description:lambda表达式静态方法引用 * Version:1.0 */ public class Test05 { public static void main(String[] args) { //实现多个参数,一个返回值的接口 //对一个静态方法的引用,语法:类::静态方法 Test1 test1 = Calculator::calculate; System.out.println(test1.test(4,5)); } } class Calculator{ public static int calculate(int a,int b ){ // 稍微复杂的逻辑:计算a和b的差值的绝对值 if (a > b) { return a - b; } return b - a; } } interface Test1{ int test(int a,int b); }
語法:物件::非靜態方法
#注意事項:
在引用的方法後面⾯,不要加上小括號。
引用的这个方法, 参数(数量、类型) 和 返回值, 必须要跟接口中定义的⼀致。
package test; /** * @author: Mercury * Date: 2022/3/21 * Time: 8:14 * Description:lambda表达式对非静态方法的引用 * Version:1.0 */ public class Test06 { public static void main(String[] args) { //对非静态方法的引用,需要使用对象来完成 Test2 test2 = new Calculator()::calculate; System.out.println(test2.calculate(2, 3)); } private static class Calculator{ public int calculate(int a, int b) { return a > b ? a - b : b - a; } } } interface Test2{ int calculate(int a,int b); }
使用场景
如果某个函数式接口中所定义的方法只是为了获取一个类的对象。此时我们就可以使用构造方法的引用,简化这个方法的实现。
语法:类名::new
注意事项:可以通过接口中的方法的参数, 区分引用不同的构造方法。
package com.cq.test; /** * @author: Mercury * Date: 2022/4/27 * Time: 10:31 * Description:lambda构造方法的引用 * Version:1.0 */ public class Test { private static class Dog{ String name; int age; //无参构造 public Dog(){ System.out.println("一个Dog对象通过无参构造被实例化了"); } //有参构造 public Dog(String name,int age){ System.out.println("一个Dog对象通过有参构造被实例化了"); this.name = name; this.age = age; } } //定义一个函数式接口,用以获取无参的对象 @FunctionalInterface private interface GetDog{ //若此方法仅仅是为了获得一个Dog对象,而且通过无参构造去获取一个Dog对象作为返回值 Dog test(); } //定义一个函数式接口,用以获取有参的对象 @FunctionalInterface private interface GetDogWithParameter{ //若此方法仅仅是为了获得一个Dog对象,而且通过有参构造去获取一个Dog对象作为返回值 Dog test(String name,int age); } // 测试 public static void main(String[] args) { //lambda表达式实现接口 GetDog lm = Dog::new; //引用到Dog类中的无参构造方法,获取到一个Dog对象 Dog dog = lm.test(); System.out.println("修狗的名字:"+dog.name+" 修狗的年龄:"+dog.age); //修狗的名字:null 修狗的年龄:0 GetDogWithParameter lm2 = Dog::new;//引用到Dog类中的有参构造,来获取一个Dog对象 Dog dog1 = lm2.test("萨摩耶",2); System.out.println("修狗的名字:"+dog1.name+" 修狗的年龄:"+dog1.age);//修狗的名字:萨摩耶 修狗的年龄:2 } }
这⾥类似于局部内部类、匿名内部类,依然存在闭包的问题。
如果在lambda表达式中引用了局部变量,则该局部变量会隐式声明为final变量。是⼀个常量,不能修改值。
以上是Java中Lambda表達式使用的方法是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!