在Java Stream流处理中,条件式结果合并是高频需求,比如过滤元素后展开子集合、根据条件生成多个结果等场景,flatMap和mapMulti是两个核心的实现方法。下面先通过一张示意图了解两者的基本处理流程:

flatMap的基本用法与特性
flatMap是Java 8就引入的流中间操作,核心作用是将流中的每个元素转换成一个新的流,再把这些流合并成一个统一的流。它要求每个元素转换后必须返回一个Stream对象,即使没有结果也需要返回空流。
比如我们需要处理一个字符串列表,把长度大于3的字符串拆分成单个字符,其他字符串直接保留,用flatMap实现的代码如下:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FlatMapDemo {
public static void main(String[] args) {
List<String> words = Arrays.asList("hello", "hi", "world", "java");
// 条件式结果合并:长度>3的拆成字符,否则保留原字符串
List<String> result = words.stream()
.flatMap(word -> {
if (word.length() > 3) {
// 拆分成字符流
return word.chars().mapToObj(c -> String.valueOf((char) c));
} else {
// 没有拆分结果,返回只包含原元素的流
return Stream.of(word);
}
})
.collect(Collectors.toList());
System.out.println(result); // 输出:[h, e, l, l, o, hi, w, o, r, l, d, java]
}
}flatMap的特点是逻辑清晰,但是对于每个元素都需要构造一个新的Stream对象,即使只返回单个元素也会产生额外的流对象开销。
mapMulti的基本用法与特性
mapMulti是Java 16引入的新方法,它的核心思路是通过回调函数直接向下游发射结果,不需要提前构造完整的Stream对象。它接收一个BiConsumer参数,第一个参数是当前元素,第二个参数是结果消费者,调用消费者的方法就可以把结果添加到下游流中。
同样实现上面的字符串拆分需求,用mapMulti的代码如下:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapMultiDemo {
public static void main(String[] args) {
List<String> words = Arrays.asList("hello", "hi", "world", "java");
// 条件式结果合并:长度>3的拆成字符,否则保留原字符串
List<String> result = words.stream()
.mapMulti((word, consumer) -> {
if (word.length() > 3) {
// 逐个发射拆分后的字符结果
for (char c : word.toCharArray()) {
consumer.accept(String.valueOf(c));
}
} else {
// 发射原元素结果
consumer.accept(word);
}
})
.collect(Collectors.toList());
System.out.println(result); // 输出:[h, e, l, l, o, hi, w, o, r, l, d, java]
}
}mapMulti不需要为每个元素创建新的Stream对象,结果直接通过消费者传递,减少了中间对象的创建开销。
两者的核心差异对比
我们可以从多个维度对比两个方法的差异,具体如下表:
| 对比维度 | flatMap | mapMulti |
|---|---|---|
| 引入版本 | Java 8 | Java 16 |
| 结果返回方式 | 必须返回Stream对象 | 通过消费者回调发射结果 |
| 中间对象开销 | 每个元素至少创建一个Stream对象 | 无额外流对象创建开销 |
| 适用场景 | 已经有现成的Stream可以返回的场景 | 需要逐个判断、逐个发射结果的场景 |
| 代码灵活性 | 逻辑相对固定,需要构造完整流 | 可以更灵活地控制结果发射逻辑 |
条件式结果合并场景的选型建议
在实际的条件式结果合并场景中,可以按照以下规则选择:
- 如果项目使用的是Java 16及以上版本,且需要根据条件逐个判断、逐个生成结果,优先选择
mapMulti,可以减少中间对象的创建,提升性能。 - 如果已经有现成的Stream对象可以直接返回,比如调用某个方法本身返回Stream,或者需要把集合直接转成流,使用
flatMap代码更简洁。 - 如果项目还在使用Java 8到Java 15的版本,只能选择
flatMap实现需求。 - 如果结果数量很少,或者性能要求不高,两者都可以使用,根据团队代码习惯选择即可。
典型场景示例
再举一个更复杂的例子:处理用户列表,根据用户的角色生成不同的权限标识,一个用户可能有多个角色,对应多个权限。
用flatMap实现的代码:
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class User {
String name;
List<String> roles;
User(String name, List<String> roles) {
this.name = name;
this.roles = roles;
}
List<String> getRoles() { return roles; }
}
public class FlatMapRoleDemo {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("张三", Arrays.asList("admin", "user")),
new User("李四", Arrays.asList("user")),
new User("王五", Arrays.asList("admin", "auditor"))
);
// 合并所有用户的权限,去重
List<String> permissions = users.stream()
.flatMap(user -> {
// 根据角色映射权限,返回权限流
return user.getRoles().stream()
.flatMap(role -> {
if ("admin".equals(role)) {
return Stream.of("create", "delete", "update");
} else if ("user".equals(role)) {
return Stream.of("view", "comment");
} else if ("auditor".equals(role)) {
return Stream.of("audit");
}
return Stream.empty();
});
})
.distinct()
.collect(Collectors.toList());
System.out.println(permissions); // 输出:[create, delete, update, view, comment, audit]
}
}用mapMulti实现的代码:
import java.util.*;
import java.util.stream.Collectors;
class User2 {
String name;
List<String> roles;
User2(String name, List<String> roles) {
this.name = name;
this.roles = roles;
}
List<String> getRoles() { return roles; }
}
public class MapMultiRoleDemo {
public static void main(String[] args) {
List<User2> users = Arrays.asList(
new User2("张三", Arrays.asList("admin", "user")),
new User2("李四", Arrays.asList("user")),
new User2("王五", Arrays.asList("admin", "auditor"))
);
// 合并所有用户的权限,去重
List<String> permissions = users.stream()
.mapMulti((user, consumer) -> {
for (String role : user.getRoles()) {
if ("admin".equals(role)) {
consumer.accept("create");
consumer.accept("delete");
consumer.accept("update");
} else if ("user".equals(role)) {
consumer.accept("view");
consumer.accept("comment");
} else if ("auditor".equals(role)) {
consumer.accept("audit");
}
}
})
.distinct()
.collect(Collectors.toList());
System.out.println(permissions); // 输出:[create, delete, update, view, comment, audit]
}
}这个场景中,mapMulti的实现不需要嵌套flatMap,逻辑更直观,也减少了多层流对象的创建,更适合这种需要多层条件判断、逐个发射结果的场景。
Java_StreamflatMapmapMulti条件式结果合并流操作修改时间:2026-05-25 21:55:32