Java Lambda 与 Stream

笔记/Java/Java基础/Java核心类库/Java Lambda 与 Stream

背景与动机#

Lambda 和 Stream 让 Java 能用更声明式的方式处理集合数据。

传统写法关注“怎么循环”,Stream 写法更关注“要得到什么结果”。这对过滤、转换、聚合这类集合操作尤其有用。

核心原理拆解#

1. Lambda 表达式#

Lambda 的基本形式是:

(参数) -> 表达式或代码块

例如:

names.forEach(name -> System.out.println(name));

如果代码块较长,可以写成:

names.forEach(name -> {
System.out.println(name);
});

2. 函数式接口#

Lambda 不是凭空存在的,它需要匹配一个只有一个抽象方法的接口,这类接口叫函数式接口。

例如 Runnable

Runnable task = () -> System.out.println("run");
task.run();

3. Stream 的常见操作#

img
img

filter 用于过滤:

names.stream()
.filter(name -> name.length() > 3);

map 用于转换:

names.stream()
.map(String::toUpperCase);

collect 用于收集结果:

List<String> result = names.stream()
.filter(name -> name.length() > 3)
.toList();

4. 中间操作和终止操作#

Stream 操作分为:

  • 中间操作:filtermap,返回新的 Stream
  • 终止操作:forEachcounttoList,触发实际计算

没有终止操作时,中间操作通常不会真正执行。

最小可运行代码示例#

import java.util.List;
public class LambdaStreamDemo {
public static void main(String[] args) {
List<String> names = List.of("Tom", "Jerry", "Alice");
List<String> result = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.toList();
result.forEach(System.out::println);
}
}

输出:

JERRY
ALICE

常见陷阱与错误示例#

1. 忘记终止操作#

names.stream()
.filter(name -> {
System.out.println(name);
return name.length() > 3;
});

没有终止操作时,过滤逻辑不会被触发。

2. 在 Stream 中写复杂副作用#

Stream 更适合表达数据转换。如果在 mapfilter 里夹杂大量修改外部状态的逻辑,代码可读性会变差。

3. 为了用 Stream 而用 Stream#

简单循环不一定需要改成 Stream。可读性比形式更重要。

面试高频问题#

1. Lambda 表达式依赖什么#

Lambda 需要匹配函数式接口,也就是只有一个抽象方法的接口。

2. Stream 的 filtermap 有什么区别#

filter 用于筛选元素,元素类型通常不变;map 用于把元素转换成另一种值。

3. Stream 中间操作什么时候执行#

通常在遇到终止操作时才会触发执行,例如 forEachcounttoList

一句话总结#

Lambda 用简洁方式表达行为,Stream 用声明式链式操作处理集合,但要注意终止操作和副作用边界。

文章目录

文章目录