Java Lambda 使用lambda简化代码,提升开发效率,代码美感
本项目基于 Java 17 + Spring Boot。启动项目后,会自动执行
LambdaShowcase,演示常见 Lamda(Lambda)用法。
1. Lamda 是什么
Lamda 是 Java 8 引入的一种简洁语法,用来表示 匿名函数,通常用于实现函数式接口(只有一个抽象方法的接口)。
传统写法(匿名内部类)代码冗长,而 Lamda 更简洁、可读性更高,尤其适用于集合处理、回调、并发等场景。
2. 基本语法
语法形式:
(参数列表) -> { 方法体 }
常见简化:
- 只有一个参数时,参数小括号可省略:
x -> x * 2 - 方法体只有一行表达式时,大括号可省略:
(a, b) -> a + b
3. 函数式接口与自定义接口
函数式接口示例:
@FunctionalInterface
interface TextFormatter {
String format(String input);
}
Lamda 实现:
TextFormatter upper = text -> text.toUpperCase();
4. Java 内置函数式接口
项目中已经示例了以下接口:
Predicate<T>:输入T,输出boolean(条件判断)Function<T, R>:输入T,输出R(转换)Consumer<T>:输入T,无返回(消费)Supplier<T>:无输入,输出T(提供)UnaryOperator<T>:一元运算(输入输出同类型)BinaryOperator<T>:二元运算(输入输出同类型)BiFunction<T, U, R>:双输入单输出
5. 方法引用与构造器引用
Lamda 可进一步简化为方法引用:
- 静态/实例方法引用:
System.out::println、String::compareToIgnoreCase - 构造器引用:
ArrayList::new
6. Stream 中的 Lamda(高频场景)
项目演示了:
filter:筛选map:映射sorted:排序reduce:归约聚合collect(groupingBy):分组summarizingInt:统计flatMap:扁平化max:比较取最大值
典型链式写法:
List<String> names = students.stream()
.filter(s -> s.score() >= 90)
.map(Student::name)
.sorted()
.toList();
7. Optional 中的 Lamda
项目演示了:
ifPresent(name -> ...)orElseGet(() -> "default")map + filter + orElse
可以减少 null 判断分支,提升可读性。
8. 并发编程中的 Lamda
项目中使用 CompletableFuture:
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> 10)
.thenApply(x -> x * 3)
.thenCombine(CompletableFuture.supplyAsync(() -> 5), Integer::sum);
这种方式可读性高,适合异步编排。
9. 变量捕获规则
Lamda 可以捕获外部局部变量,但变量必须是 effectively final(事实最终),即赋值后不再修改。
int base = 10;
Function<Integer, Integer> addBase = x -> x + base;
如果后续重新给 base 赋值,代码将无法编译。
10. 本项目代码
/**
* Java Lambda usage showcase.
*/
public class LambdaShowcase {
@FunctionalInterface
interface TextFormatter {
String format(String input);
}
record Student(String name, int age, int score, String clazz) {
}
public void runAll() {
printTitle("1. 基础 Lambda 语法");
basicLambdaSyntax();
printTitle("2. 自定义函数式接口");
customFunctionalInterface();
printTitle("3. Java 内置函数式接口");
builtInFunctionalInterfaces();
printTitle("4. 方法引用与构造器引用");
methodAndConstructorReference();
printTitle("5. Stream 流式处理");
streamOperations();
printTitle("6. Optional 场景");
optionalUsage();
printTitle("7. 并发与异步 Lambda");
asyncLambdaUsage();
printTitle("8. 变量捕获(effectively final)");
variableCapture();
}
private void basicLambdaSyntax() {
Runnable runnable = () -> System.out.println("Runnable Lambda: hello");
runnable.run();
List<String> names = new ArrayList<>(Arrays.asList("Tom", "Jerry", "Alice"));
names.sort((a, b) -> a.compareToIgnoreCase(b));
System.out.println("排序后: " + names);
}
private void customFunctionalInterface() {
TextFormatter upperFormatter = text -> text == null ? "" : text.toUpperCase();
TextFormatter decorateFormatter = text -> "[[" + text + "]]";
System.out.println("大写格式化: " + upperFormatter.format("lambda"));
System.out.println("装饰格式化: " + decorateFormatter.format("java"));
}
private void builtInFunctionalInterfaces() {
Predicate<Integer> isAdult = age -> age >= 18;
Function<String, Integer> toLength = String::length;
Consumer<String> printer = text -> System.out.println("消费数据: " + text);
Supplier<Long> now = System::currentTimeMillis;
UnaryOperator<Integer> square = num -> num * num;
BinaryOperator<Integer> add = Integer::sum;
BiFunction<Integer, Integer, String> joinAsText = (a, b) -> a + " + " + b + " = " + (a + b);
System.out.println("18 岁是否成年: " + isAdult.test(18));
System.out.println("字符串长度: " + toLength.apply("functional"));
printer.accept("Consumer 执行成功");
System.out.println("当前时间戳: " + now.get());
System.out.println("平方计算: " + square.apply(9));
System.out.println("加法结果: " + add.apply(3, 7));
System.out.println("BiFunction 输出: " + joinAsText.apply(5, 8));
}
private void methodAndConstructorReference() {
List<String> words = new ArrayList<>(Arrays.asList("pear", "apple", "banana"));
words.sort(String::compareToIgnoreCase);
words.forEach(System.out::println);
Supplier<List<String>> listFactory = ArrayList::new;
List<String> builtByConstructorRef = listFactory.get();
builtByConstructorRef.add("created-by-constructor-reference");
System.out.println(builtByConstructorRef);
}
private void streamOperations() {
List<Student> students = Arrays.asList(
new Student("Alice", 20, 91, "A"),
new Student("Bob", 19, 84, "A"),
new Student("Cindy", 21, 95, "B"),
new Student("David", 18, 78, "B"),
new Student("Eric", 20, 88, "A")
);
List<String> excellentNames = students.stream()
.filter(s -> s.score() >= 90)
.map(Student::name)
.sorted()
.toList();
System.out.println("90+ 学生: " + excellentNames);
int totalScore = students.stream()
.map(Student::score)
.reduce(0, Integer::sum);
System.out.println("总分: " + totalScore);
Map<String, List<Student>> grouped = students.stream()
.collect(Collectors.groupingBy(Student::clazz));
System.out.println("按班级分组: " + grouped);
IntSummaryStatistics stats = students.stream()
.collect(Collectors.summarizingInt(Student::score));
System.out.println("统计信息: " + stats);
List<String> chars = Arrays.asList("ab", "cd", "ef").stream()
.flatMap(s -> s.chars().mapToObj(c -> String.valueOf((char) c)))
.toList();
System.out.println("flatMap 拆分字符: " + chars);
Student topOne = students.stream()
.max(Comparator.comparingInt(Student::score))
.orElseThrow();
System.out.println("最高分学生: " + topOne);
}
private void optionalUsage() {
Optional<String> maybeName = Optional.of("Lambda");
maybeName.ifPresent(name -> System.out.println("ifPresent: " + name));
String fallback = Optional.<String>empty()
.orElseGet(() -> "default-name");
System.out.println("orElseGet 结果: " + fallback);
int length = maybeName
.map(String::length)
.filter(size -> size > 3)
.orElse(0);
System.out.println("Optional map/filter 结果: " + length);
}
private void asyncLambdaUsage() {
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> 10)
.thenApply(x -> x * 3)
.thenCombine(CompletableFuture.supplyAsync(() -> 5), Integer::sum);
try {
System.out.println("CompletableFuture 结果: " + future.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("线程被中断", e);
} catch (ExecutionException e) {
throw new RuntimeException("异步任务执行失败", e);
}
}
private void variableCapture() {
int base = 10;
Function<Integer, Integer> addBase = x -> x + base;
System.out.println("捕获局部变量结果: " + addBase.apply(5));
System.out.println("注意: base 不能在后续被重新赋值,否则无法编译");
}
private void printTitle(String title) {
System.out.println();
System.out.println("==== " + title + " ====");
}
}
或运行 LamdaDemoApplication 主类。控制台会分章节输出各类 Lamda 使用案例。
11. 学习建议
按以下顺序练习:
- 先掌握四大基础接口:
Predicate/Function/Consumer/Supplier - 再掌握 Stream 链式处理(
filter-map-collect) - 最后学习
CompletableFuture异步组合
当你看到匿名内部类时,可以尝试重构为 Lamda;当 Lamda 只有方法转发时,再重构为方法引用。