多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

详解Java中的lambda表达式

详解Java中的lambda表达式 lambda表达式概念Java中为了更方便的传递和处理代码块更好的支持函数式编程引入了lambda表达式通过lambda可以在Java中实现类似于回调函数的功能通过lambda表达式我们可以在任意的地方调用需要的代码块如果没有lambda表达式的话就需要通过对象来调用方法或者通过类来调用静态方法但是这种做法在特殊的地方违反面向对象设计的原则——也就是说并不是所有需要的代码块都可以封装在类中或者在类内静态实现每个类应该是有其具体的职责和封装对象的但是在引入lambda之前Java中的某些类库就是这样做的。lambda本质上是一个匿名函数但是这个方法是不独立执行的而是用于实现函数式接口只有一个抽象方法的接口定义的另一种方法所以lambda会产生一个匿名类lambda表达式跟两个概念息息相关一个是lambda表达式本身另一个就是函数式接口lambda表达式首先说lambda表达式lambda表达式通过箭头符号-定义箭头左边定义表达式的参数右边定义表达式的执行动作举个栗子//无参表达式 ()-0.123; ()-Math.random().100; //一个参数的lambda表达式 (n)-(n%2)0; n-n2; (int n)-n; //多个参数 (n,m)-nm; (int n,int m,int j)-nmj;从上面的栗子中可以看出基本的lambda表达式的语法规则lambda表达式的参数类型个数不受限制对于左侧传入的参数进行右侧的表达式计算返回的是右侧表达式计算结果当lambda表达式中可以推断出参数类型的时候将不用声明参数类型当只有一个参数的时候可以省略括号同时lambda中也可以执行一个代码块int age,String name-{ System.out.println(name); age; return age; }当右侧为代码块的时候必须使用return语句返回lambda表达式的执行结果函数式接口函数是接口是lambda表达式中另一个重要的概念所谓函数式接口就是只有一个抽象方法的接口这里需要注意的是函数式接口只规定了接口中只能有一个抽象方法而不是只有一个方法Java8以后接口中可以声明静态方法和默认方法这些方法都不是抽象方法同时在Java中对lambda能做的只能是将lambda表达式转化为函数式接口不能独立声明lambda表达式泛型函数式接口lambda表达式本身不支持泛型编程但是接口可以泛型化而lambda表达式可以实现这种泛型接口interface IntfacT{ default int fds(){return 0;}; T getsum(T a,T b); public static int dfs(int c,int d){return 0;}; } public class LambdaTest { public static void main(String[]args) { Intfac Integer intfac(a,b)-ab; IntfacDouble intfac1(a,b)-a-b; int cintfac.getsum(1,2); Double rintfac1.getsum(1D,2D); System.out.println(c); } }将lambda表达式作为参数当方法参数的类型为函数式接口的时候就可以将与该函数式接口兼容的lambda表达式当作参数传递给该方法该lambda表达式可以为表达式lambda可以为lambda块下面通过一个完整的实战示例演示如何将lambda表达式作为参数传递给自定义方法实现列表过滤和排序import java.util.ArrayList; import java.util.Collections; import java.util.List; public class LambdaParamDemo { // 自定义过滤方法接收函数式接口作为参数 public static ListInteger filter(ListInteger list, IntPredicate predicate) { ListInteger result new ArrayList(); for (Integer num : list) { if (predicate.test(num)) { result.add(num); } } return result; } // 自定义排序方法接收函数式接口作为参数 public static void sort(ListInteger list, IntComparator comparator) { Collections.sort(list, comparator::compare); } // 函数式接口判断整数是否满足条件 interface IntPredicate { boolean test(int n); } // 函数式接口比较两个整数 interface IntComparator { int compare(int a, int b); } public static void main(String[] args) { ListInteger numbers new ArrayList(); numbers.add(5); numbers.add(2); numbers.add(8); numbers.add(1); numbers.add(9); // 将lambda表达式作为参数传递给filter方法过滤出偶数 ListInteger evens filter(numbers, n - n % 2 0); System.out.println(偶数列表 evens); // 运行结果偶数列表[2, 8] // 将lambda表达式作为参数传递给filter方法过滤出大于3的数 ListInteger bigNums filter(numbers, n - n 3); System.out.println(大于3的列表 bigNums); // 运行结果大于3的列表[5, 8, 9] // 将lambda表达式作为参数传递给sort方法按降序排序 sort(numbers, (a, b) - b - a); System.out.println(降序排序 numbers); // 运行结果降序排序[9, 8, 5, 2, 1] // 将lambda表达式作为参数传递给sort方法按升序排序 sort(numbers, (a, b) - a - b); System.out.println(升序排序 numbers); // 运行结果升序排序[1, 2, 5, 8, 9] } }在上面的示例中filter和sort方法的参数类型都是函数式接口因此可以直接将lambda表达式作为实参传入。这种方式让代码更加简洁灵活无需为每种过滤或排序规则单独编写方法体现了lambda表达式作为参数传递的核心价值。方法引用静态方法引用对象方法引用总结与常见错误lambda表达式和函数式接口是Java函数式编程的两大基石。lambda表达式本质上是匿名函数用于实现函数式接口函数式接口则只允许有一个抽象方法但可以包含默认方法和静态方法。二者配合使用可以让代码更加简洁、灵活尤其在集合过滤、排序和回调等场景中优势明显。不过初学者在使用过程中经常踩坑下面列出3个常见错误及其修正方法。错误一lambda表达式捕获的变量被修改lambda表达式只能捕获effectively final有效final的局部变量即变量一旦赋值后不再改变。如果尝试在lambda内部修改外部变量编译会直接报错。// 错误代码编译报错无法在lambda中修改外部变量 int count 0; Runnable task () - { count; // 编译错误Local variable count defined in an enclosing scope must be final or effectively final }; task.run();// 修正代码使用原子类或数组包装可变状态 AtomicInteger count new AtomicInteger(0); Runnable task () - { count.incrementAndGet(); }; task.run(); System.out.println(count.get()); // 运行结果1错误二重载方法导致lambda表达式歧义当同一个类中存在多个重载方法且参数都是不同的函数式接口时直接传入lambda表达式会导致编译器无法确定应该匹配哪个重载版本。// 错误代码编译报错lambda表达式无法匹配重载方法 public class OverloadDemo { public static void execute(IntConsumer consumer) { consumer.accept(1); } public static void execute(LongConsumer consumer) { consumer.accept(1L); } public static void main(String[] args) { execute(x - System.out.println(x)); // 编译错误ambiguous method call } }// 修正代码显式类型转换消除歧义 public class OverloadDemo { public static void execute(IntConsumer consumer) { consumer.accept(1); } public static void execute(LongConsumer consumer) { consumer.accept(1L); } public static void main(String[] args) { execute((IntConsumer) (x - System.out.println(x))); // 运行结果1 } }错误三误用接口默认方法导致函数式接口失效函数式接口只允许有一个抽象方法但可以包含默认方法和静态方法。初学者容易把默认方法误当成抽象方法或者在一个接口中声明多个抽象方法导致接口不再是函数式接口无法用lambda表达式实现。// 错误代码接口包含两个抽象方法无法使用lambda表达式实现 interface Calculator { int add(int a, int b); int subtract(int a, int b); // 第二个抽象方法导致接口不是函数式接口 } // 编译错误Cannot convert to a functional interface Calculator calc (a, b) - a b;// 修正代码只保留一个抽象方法其余方法改为默认方法 interface Calculator { int add(int a, int b); default int subtract(int a, int b) { return a - b; } } Calculator calc (a, b) - a b; System.out.println(calc.add(3, 5)); // 运行结果8 System.out.println(calc.subtract(3, 5)); // 运行结果-2
返回列表