【Java】深入浅出 Lambda 表达式,从入门到实操
哈喽各位小伙伴,近期一直在梳理 Java8 核心新特性内容,今天就来详细聊聊 Java8 标志性语法 ——Lambda 表达式。Lambda 是函数式编程落地 Java 的关键,用好它能大幅精简冗余代码,尤其是在接口回调、集合遍历、多线程场景中提升编码效率。
一、初识 Lambda 表达式
Lambda 是 Java8 新增的匿名方法语法,核心作用:把一段代码块当作方法参数进行传递,延迟执行逻辑,摆脱传统匿名内部类繁琐的格式书写。
基础语法格式
(参数列表) -> 方法体
():存放方法入参,无参数时空括号;单个参数可省略括号->:Lambda 专属箭头标识符,分割参数和方法体- 方法体:单行代码可省略大括号与 return,多行必须用
{}包裹
最简示例(无参 Lambda):
// 无参数,单行输出
() -> System.out.println("云扬");
二、结合 Runnable 接口理解 Lambda
Runnable是典型函数式接口,源码被@FunctionalInterface注解修饰,规定接口中仅有一个抽象方法,只有满足这个条件的接口,才支持 Lambda 实现。
1. Runnable 接口源码
@FunctionalInterface
public interface Runnable {
void run();
}
@FunctionalInterface注解会在编译期校验接口抽象方法数量,避免误添加多个抽象方法导致 Lambda 无法使用。
2. Java8 之前:匿名内部类创建线程
传统写法冗余,需要重写完整接口方法,代码臃肿:
public class LambdaDemo {
public static void main(String[] args) {
// 匿名内部类写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("传统匿名内部类启动线程");
}
}).start();
}
}
3. Lambda 简化写法
借助 Lambda 省略接口实现类,一行搞定线程创建:
public class LambdaDemo {
public static void main(String[] args) {
// Lambda简化Runnable实现
new Thread(() -> System.out.println("Lambda启动线程")).start();
}
}
对比能直观感受到 Lambda 精简代码的优势,这也是日常开发中最常用的场景之一。
三、Lambda 四种常用使用场景
Lambda 不只是用来创建线程,日常开发中可用于变量赋值、返回值、数组元素、方法入参四种场景。
public class LambdaUse {
public static void main(String[] args) {
// 场景1:赋值给接口变量
Runnable run = () -> {
System.out.println("Lambda赋值变量");
};
run.run();
// 场景2:作为方法入参(前面线程示例)
new Thread(() -> System.out.println("作为方法参数")).start();
// 场景3:Lambda作为数组元素
Runnable[] arr = {
() -> System.out.println("数组元素1"),
() -> System.out.println("数组元素2")
};
arr[0].run();
}
// 场景4:方法返回Lambda表达式
public static Runnable getRun() {
return () -> System.out.println("Lambda作为返回值");
}
}
四、Lambda 变量作用域细节
1. 外部变量限制:final/effectively final
Lambda不会开辟独立作用域,内部引用局部变量时,变量必须是final或者等效 final(只赋值一次,隐性 final),不允许直接在 Lambda 内修改基础类型局部变量。
错误示例:
public class ScopeTest {
public static void main(String[] args) {
int num = 10;
Runnable r = () -> {
// 编译报错:num非final,不能修改
num++;
System.out.println(num);
};
}
}
2. 三种突破变量修改限制的方案
实际开发中需要在 Lambda 修改数值,推荐三种解决方式:
- 静态 static 变量:静态变量存放在方法区,不受 final 约束
public class VarDemo {
static int count = 0;
public static void main(String[] args) {
Runnable r = () -> {
count++;
System.out.println(count);
};
r.run();
}
}
- AtomicInteger 原子类(推荐,多线程安全):JUC 并发包工具,原子自增
import java.util.concurrent.atomic.AtomicInteger;
public class VarDemo {
public static void main(String[] args) {
AtomicInteger count = new AtomicInteger(0);
Runnable r = () -> {
count.incrementAndGet();
System.out.println(count.get());
};
r.run();
}
}
- 数组包装:数组是引用类型,数组地址不变即可修改内部元素
public class VarDemo {
public static void main(String[] args) {
int[] arr = {0};
Runnable r = () -> {
arr[0]++;
System.out.println(arr[0]);
};
r.run();
}
}
五、Lambda 中 this 关键字
再次强调:Lambda 没有独立作用域,this指向定义 Lambda 的外部类实例,和匿名内部类完全不同(匿名内部类 this 指向自身内部类对象)。
public class ThisDemo {
public void test() {
// Lambda的this = ThisDemo类实例
Runnable r = () -> System.out.println(this);
r.run();
}
public static void main(String[] args) {
new ThisDemo().test();
}
}
六、文末小结
- Lambda 依托 函数式接口(@FunctionalInterface) 使用,单一抽象方法是前提;
- 核心作用:简化匿名内部类,实现函数式编程,代码轻量化;
- 变量规则:局部变量要求 effectively final,需要修改可用原子类、数组、静态变量;
- this 指向:外层宿主对象,无独立内部类 this。



