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中文网其他相关文章!