Java Lambda 表达式简介
·
Lambda 表达式是 Java 8 引入的重要特性,它是一种匿名函数,可以作为方法参数传递或赋值给变量。Lambda 表达式让代码更加简洁,特别适用于函数式编程场景。
1. 基本语法
(parameters) -> expression
// 或
(parameters) -> { statements; }
- parameters: 参数列表(可以省略类型)
- ->: Lambda 操作符
- expression/statements: 函数体(简单表达式可以省略花括号)
2. 核心概念:函数式接口
java Lambda 表达式只能用于函数式接口(Functional Interface):
- 只包含一个抽象方法的接口
- 可以使用
@FunctionalInterface注解标记
常见的函数式接口:
| 接口 | 抽象方法 | 用途 |
|---|---|---|
Function<T,R> |
R apply(T t) |
输入T,输出R |
Consumer<T> |
void accept(T t) |
消费T,无返回值 |
Supplier<T> |
T get() |
无输入,返回T |
Predicate<T> |
boolean test(T t) |
判断T是否满足条件 |
Runnable |
void run() |
无参数无返回值 |
这些接口为什么叫"函数式"接口?因为这些接口本质上就代表一个函数:
- 输入:参数列表
- 输出:返回值
- 功能:方法体要做的事情
Lambda 表达式让我们可以直接写出这个"函数",而不需要包装在类和方法中:
- Lambda 表达式 = 函数式接口中抽象方法的实现
- 编译器会自动将 Lambda 表达式转换为对应的函数式接口实例
3. 常见用法示例
3.1. 替代匿名内部类
传统方式(匿名内部类):
// 创建一个 Consumer 接口的实现
Consumer<String> printer = new Consumer<String>() {
@Override
public void accept(String message) {
System.out.println(message);
}
};
printer.accept("Hello"); // 输出: Hello
Lambda 表达式方式:
// 同样的功能,但代码简洁多了
Consumer<String> printer = (String message) -> {
System.out.println(message);
};
// 还可以进一步简化(编译器能推断出类型,所以可以省略输入参数类型String)
Consumer<String> printer2 = message -> System.out.println(message);
printer2.accept("Hello"); // 输出: Hello
3.2. 集合操作 - forEach
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 传统 for 循环
for (String name : names) {
System.out.println(name);
}
// Lambda + forEach
names.forEach(name -> System.out.println(name));
// 方法引用(更简洁)
names.forEach(System.out::println);
3.3. Stream API 过滤和转换
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 过滤偶数并平方
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0) // Predicate
.map(n -> n * n) // Function
.collect(Collectors.toList());
System.out.println(result); // [4, 16, 36, 64, 100]
3.4. 自定义函数式接口
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
public class Main {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
System.out.println(add.calculate(5, 3)); // 8
System.out.println(multiply.calculate(5, 3)); // 15
}
}
3.5. 带参数的 Lambda
// 无参数: Supplier 接口:无参数,有返回值
Supplier<String> greeting = () -> "Hello, Lambda!";
System.out.println(supplier.get()); // Hello Lambda
// 单个参数:Consumer 接口:一个参数,无返回值
Consumer<String> consumer = (str) -> System.out.println(str);
// 或者省略括号
Consumer<String> consumer2 = str -> System.out.println(str);
// 多个参数:BiFunction 接口:两个参数,有返回值
BiFunction<Integer, Integer, Integer> adder = (a, b) -> a + b;
System.out.println(adder.apply(3, 5)); // 8
3.6. 多行 Lambda 表达式
// 方法体有多行
List<String> words = Arrays.asList("hello", "world", "java");
words.forEach(word -> {
String upper = word.toUpperCase();
System.out.println("Original: " + word + ", Upper: " + upper);
});
3.7 简化写法
1. 方法体只有一行,可以省略大括号和 return 关键字
// 方法体只有一行:可以省略大括号和 return 关键字
Function<Integer, Integer> square = x -> x * x;
// 等价于
Function<Integer, Integer> square2 = x -> { return x * x; };
2. 自动类型推断
// 编译器能推断出类型,所以可以省略
Function<String, Integer> parser = s -> Integer.parseInt(s);
// 而不是
Function<String, Integer> parser = (String s) -> Integer.parseInt(s);
3. 方法引用(更简洁)
// Lambda 表达式
Function<String, Integer> parser1 = s -> Integer.parseInt(s);
// 方法引用(等价)
Function<String, Integer> parser2 = Integer::parseInt;
3.8. 实际应用场景
1. 事件处理:
button.addActionListener(e -> System.out.println("Button clicked!"));
2. 排序:
List<Person> people = // ... 初始化数据
people.sort((p1, p2) -> p1.getAge() - p2.getAge());
// 或使用方法引用
people.sort(Comparator.comparing(Person::getAge));
3. 线程创建:
Thread thread = new Thread(() -> {
// 执行任务
System.out.println("Running in thread: " + Thread.currentThread().getName());
});
thread.start();
4. Lambda 表达式的变量作用域
Lambda 表达式可以访问外部变量,但有以下限制:
public void scopeExample() {
final int x = 10;
int y = 20;
// 可以访问 final 变量
Runnable r1 = () -> System.out.println(x);
// 可以访问"effectively final"变量(该变量后续不能被修改)
Runnable r2 = () -> System.out.println(y);
// y = 30; // 如果取消注释,上面的 r2 会编译错误
// 不能修改外部局部变量
// Runnable r3 = () -> y = 30; // 编译错误
}
5. 总结
优势总结
- 代码简洁:减少样板代码
- 可读性好:逻辑更清晰
- 支持函数式编程:便于并行处理
- 提高开发效率:配合 Stream API 强大功能
注意事项
- Lambda 表达式不是万能的,过度使用可能降低代码可读性
- 性能方面,首次调用会有一定开销,但后续调用性能良好
- 调试时堆栈信息可能不如传统方法清晰
6. 相关文档
1.Java常用函数式接口简介: https://blog.csdn.net/taotiezhengfeng/article/details/157020377
2.Collectors.toMap() 用法简介: https://blog.csdn.net/taotiezhengfeng/article/details/156993078
更多推荐



所有评论(0)