Skip to main content

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::printlnString::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. 学习建议

按以下顺序练习:

  1. 先掌握四大基础接口:Predicate / Function / Consumer / Supplier
  2. 再掌握 Stream 链式处理(filter-map-collect
  3. 最后学习 CompletableFuture 异步组合

当你看到匿名内部类时,可以尝试重构为 Lamda;当 Lamda 只有方法转发时,再重构为方法引用。