Lambda表达式说爱你不容易

你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累


作为一个多年java开发经验的过来人讲,我是真的是不喜欢用Lambda表达式,但是,奈何代码写的确实简洁呀!下面我们一起来看看Lambda表达式,那些又爱又恨的地方。


Java 8 引入了 Lambda 表达式,它是函数式编程的重要特性之一。Lambda 表达式允许你以更加简洁的方式表达行为和操作,尤其是在与 Stream API、集合框架、并发编程 等一起使用时,能够大大提高代码的可读性和可维护性。


01
Lambda 表达式的基本语法


Lambda 表达式的基本语法如下:

(parameters) -> expression

或者

(parameters) -> { statements; }
  • parameters:参数列表,可以是一个或多个。

  • ->:Lambda 操作符,表示“传递参数给方法”。

  • expression:Lambda 表达式体,可以是一个表达式或一个代码块。


02
Lambda 表达式的构成


参数列表:Lambda 表达式的输入参数,类似于方法的参数列表。

箭头操作符 (->):分隔符,左边是参数列表,右边是方法体。

方法体:Lambda 表达式的主体部分,可以是单行的表达式或多行的代码块。


无参数、无返回值的 Lambda 表达式

() -> System.out.println("Hello, World!");

这个 Lambda 表达式表示一个无参数且无返回值的方法。


带参数的 Lambda 表达式

(int a, int b) -> a + b;

表示一个接受两个参数 a 和 b 并返回它们之和的方法。


带有代码块的 Lambda 表达式

(int a, int b) -> {    System.out.println("Adding two numbers: " + a + " + " + b);    return a + b;};

这个 Lambda 表达式包含了一个代码块,做了额外的操作并返回计算结果。


03
Lambda 表达式的使用场景


替代匿名类

在 Java 8 之前,很多接口的实现都需要使用匿名类。使用 Lambda 表达式,可以将代码更加简洁地表达出来。

匿名类示例:

new Thread(new Runnable() {    @Override    public void run() {        System.out.println("Hello from thread");    }}).start();

Lambda 表达式示例:

new Thread(() -> System.out.println("Hello from thread")).start();


与集合框架配合使用

在 Java 8 中,Lambda 表达式常与集合框架、流操作(Stream API)结合使用,尤其是对集合的过滤、排序、遍历等操作。

例如,使用 forEach 遍历集合:

List<String> list = Arrays.asList("apple""banana""cherry");list.forEach(item -> System.out.println(item));


Stream API

Lambda 表达式与 Stream API 一起使用时,能更轻松地进行函数式编程操作,如过滤、映射、排序等。

示例:过滤和排序

List<Integer> numbers = Arrays.asList(123456789);numbers.stream()       .filter(n -> n % 2 == 0)        // 过滤出偶数       .sorted()                       // 排序       .forEach(n -> System.out.println(n)); // 打印结果


04
函数式接口(Functional Interface)


Lambda 表达式常常与 函数式接口 一起使用。函数式接口是指仅包含一个抽象方法的接口,可以有多个默认方法和静态方法。

定义函数式接口

@FunctionalInterfacepublic interface MyFunctionalInterface {    void myMethod();}


这个接口仅有一个抽象方法,因此它是一个有效的函数式接口,可以用 Lambda 表达式实现。

常见的函数式接口

  • Runnable:无参数,无返回值,适用于线程执行。

  • Comparator<T>:用于比较对象,通常在排序时使用。

  • Predicate<T>:接收一个参数并返回一个布尔值,常用于条件判断。

  • Function<T, R>:接收一个参数并返回一个结果。

  • Consumer<T>:接收一个参数并进行操作,但不返回任何结果。

  • Supplier<T>:不接受任何参数,返回一个结果。


05
Lambda 表达式与方法引用


在 Java 8 中,方法引用(Method Reference)是一种简化 Lambda 表达式的方式。方法引用通过直接使用类或对象的方法来代替 Lambda 表达式中的函数体部分。

Lambda 表达式:

list.forEach(s -> System.out.println(s));

方法引用:

list.forEach(System.out::println);


常见的三种方法引用

静态方法引用:ClassName::staticMethod

Arrays.sort(arrayInteger::compareTo);


实例方法引用:instance::instanceMethod

String str = "Hello";Arrays.sort(array, str::compareTo);


构造方法引用:ClassName::new

Supplier<List<String>> listSupplier = ArrayList::new;List<String> list = listSupplier.get();


06
Lambda 表达式的优势


简洁性:Lambda 表达式能显著简化代码,减少冗余的匿名类代码,使得代码更易于理解和维护。

函数式编程支持:Lambda 提供了函数式编程的风格,使得可以通过更灵活的方式处理数据,特别是在流(Stream)操作中。

并行处理:与 Stream API 结合,可以轻松地实现并行计算,充分利用多核处理器。

延迟计算:与 Stream 等结合,允许懒加载和惰性计算,提高性能。


07
Lambda 表达式的限制


无法访问外部变量的改变:Lambda 表达式不能修改外部局部变量,除非这些变量是 final 或者“有效 final”(即在 Lambda 表达式之前不被修改)。

int x = 10;// 以下代码会报错,因为变量 x 在 Lambda 表达式内不能被修改Runnable r = () -> { x = 20; };

调试困难:Lambda 表达式往往无法直接进行调试,代码的可追踪性较差。

过度使用:尽管 Lambda 表达式能简化代码,但过度使用可能导致代码过于简短,甚至难以理解。在某些场景下,传统的命令式编程方式可能更为清晰。

日志打印难受:日志打印的时候,很难打印出具体是哪个地方出现了问题,特别是一连串的Lambda 表达式排在同一行中


08
总结


  • Lambda 表达式 是 Java 8 中的重要新特性,能够让代码更加简洁、可读,并且支持函数式编程风格。

  • 它广泛应用于集合处理、事件监听、并发编程等场景。

  • 配合 Stream API,Lambda 能够使代码更加高效和简洁。

  • 需要注意 Lambda 表达式的适用场景,避免滥用,保持代码的清晰和易维护性。

今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!

END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

谈谈id那些事(五)——美团的 Leaf 的ID生成


一个阿里二面面试官必问的问题


谈谈id那些事(三)——阿里巴巴的 TDDL的ID生成


分享面试:mysql数据库索引失效的情况


面试常被忽略的问题——内存区域划分