Lambda
Lambda 表达式是 Java 8 引入的重要特性,本质是匿名函数(没有名称的函数),用于简化函数式接口的实现,使代码更简洁、紧凑。它特别适合处理集合的遍历、过滤、映射等操作,是函数式编程在 Java 中的核心体现。
一、Lambda 表达式的基本概念
1. 函数式接口(前提)
Lambda 表达式只能用于函数式接口—— 即只包含一个抽象方法的接口(可包含默认方法或静态方法)。Java 内置了大量函数式接口(如 Runnable
、Comparator
、Consumer
等),也可自定义。
// 自定义函数式接口(只有一个抽象方法)
@FunctionalInterface // 注解可校验是否为函数式接口
interface MathOperation {int operate(int a, int b);
}
2. Lambda 语法结构
Lambda 表达式的语法格式:
(参数列表) -> { 方法体 }
- 参数列表:与函数式接口中抽象方法的参数一致,可省略参数类型(编译器自动推断)。
->
:箭头符号,分隔参数列表和方法体。- 方法体:实现抽象方法的逻辑,若只有一行代码可省略
{}
和return
(若有返回值)。
二、Lambda 表达式的简化写法
根据场景不同,Lambda 可逐步简化,以下是常见形式:
1. 完整写法(带参数类型和方法体)
MathOperation addition = (int a, int b) -> {return a + b;
};
2. 省略参数类型(编译器自动推断)
MathOperation subtraction = (a, b) -> {return a - b;
};
3. 方法体只有一行代码(省略 {}
和 return
)
MathOperation multiplication = (a, b) -> a * b; // 自动返回结果
4. 无参数的情况
// Runnable 接口(无参数,无返回值)
Runnable runnable = () -> System.out.println("Lambda 运行中");
5. 单个参数(可省略参数的括号)
// Consumer 接口(单个参数,无返回值)
Consumer<String> consumer = s -> System.out.println(s);
三、Lambda 表达式的核心应用场景
1. 替代匿名内部类
传统匿名内部类代码冗长,Lambda 可大幅简化:
传统方式(匿名内部类):
// 线程创建
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程运行");}
}).start();
Lambda 方式:
new Thread(() -> System.out.println("线程运行")).start();
2. 集合遍历与操作
结合 Java 8 新增的 Stream API
,Lambda 可简洁处理集合的遍历、过滤、排序等:
示例 1:遍历集合
List<String> list = Arrays.asList("apple", "banana", "cherry");// 传统 for 循环
for (String s : list) {System.out.println(s);
}// Lambda + forEach
list.forEach(s -> System.out.println(s));
// 更简化(方法引用)
list.forEach(System.out::println);
示例 2:集合排序
List<Integer> numbers = Arrays.asList(3, 1, 2);// 传统方式(匿名内部类)
Collections.sort(numbers, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1 - o2; // 升序}
});// Lambda 方式
Collections.sort(numbers, (a, b) -> a - b); // 升序
// 更简化(方法引用)
numbers.sort(Integer::compareTo);
示例 3:过滤与映射(Stream API)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 过滤偶数并计算平方和
int sum = numbers.stream().filter(n -> n % 2 == 0) // 过滤偶数.map(n -> n * n) // 计算平方.reduce(0, Integer::sum); // 求和System.out.println(sum); // 输出:2² + 4² + 6² = 4 + 16 + 36 = 56
3. 自定义函数式接口
通过自定义函数式接口,可将 Lambda 作为参数传递,实现灵活的业务逻辑:
// 自定义函数式接口(处理字符串)
@FunctionalInterface
interface StringProcessor {String process(String s);
}// 工具方法:接收 Lambda 作为参数
public static String handleString(String s, StringProcessor processor) {return processor.process(s);
}// 使用
public static void main(String[] args) {// 转换为大写String upper = handleString("hello", s -> s.toUpperCase());System.out.println(upper); // HELLO// 反转字符串String reversed = handleString("hello", s -> new StringBuilder(s).reverse().toString());System.out.println(reversed); // olleh
}
四、Lambda 表达式的底层原理
Lambda 表达式在编译后不会生成匿名内部类,而是通过 invokedynamic
指令动态生成一个函数式接口的实现类,本质是语法糖,但比匿名内部类更高效(减少类文件生成)。
例如,以下 Lambda 表达式:
Runnable r = () -> System.out.println("Lambda");
编译后会生成一个类似以下的实现类(由 JVM 动态创建,不在字节码中显式存在):
class Lambda$1 implements Runnable {@Overridepublic void run() {System.out.println("Lambda");}
}
五、Lambda 表达式的注意事项
访问外部变量:Lambda 可访问外部的
final
或事实上 final(即未声明为final
但未被修改)的变量。int num = 10; // 事实上 final(未被修改) Runnable r = () -> System.out.println(num); // 合法 // num = 20; // 若修改,编译报错
this
关键字:Lambda 中的this
指向包围它的外部类对象,而匿名内部类的this
指向自身实例。方法引用(进一步简化):若 Lambda 方法体只是调用一个已存在的方法,可使用方法引用(
::
语法)进一步简化:// Lambda 方式 list.forEach(s -> System.out.println(s)); // 方法引用方式(等价) list.forEach(System.out::println);
常见方法引用类型:
- 静态方法引用:
ClassName::staticMethod
(如Integer::parseInt
)。 - 实例方法引用:
instance::method
(如str::length
)。 - 类的实例方法引用:
ClassName::method
(如String::equals
)。 - 构造方法引用:
ClassName::new
(如ArrayList::new
)。
- 静态方法引用:
总结
Lambda 表达式的核心价值是简化代码和支持函数式编程,尤其在集合操作和事件处理中优势明显。其使用前提是函数式接口,语法简洁灵活,可根据场景逐步简化。
掌握 Lambda 表达式需要理解:
- 函数式接口是基础。
- 语法格式:
(参数) -> 方法体
。 - 常见应用:替代匿名内部类、集合遍历与 Stream 操作。
- 方法引用是 Lambda 的进一步简化。
Lambda 表达式是 Java 现代化的重要一步,与 Stream API、Optional 等特性结合,能显著提升代码的可读性和开发效率。