mono map
// 使用 map(同步)
Mono<String> result1 = Mono.just("user1")
.map(id -> id.toUpperCase()); // 同步操作
// 使用 flatMap(异步)
Mono<String> result2 = Mono.just("user1")
.flatMap(id -> fetchUserAsync(id)); // fetchUserAsync 返回 Mono<String>
Mono.just("alice")
.map(String::toUpperCase) // 同步: 转大写
.flatMap(name -> saveToDatabase(name)) // 异步: 存数据库
.subscribe(
result -> System.out.println("Saved: " + result),
error -> System.err.println("Error: " + error)
);
// 错误示范(阻塞主线程)
Mono.just("data").map(s -> blockingCall(s));
// 正确做法
Mono.just("data")
.flatMap(s -> Mono.fromCallable(() -> blockingCall(s))
.subscribeOn(Schedulers.boundedElastic()));
在 Project Reactor 中,`Mono` 的 `map` 方法是一个 **同步转换操作符**,用于对 `Mono` 中的元素进行一对一的转换。它的核心特点是 **非阻塞、同步执行**,适用于简单的数据转换场景。以下是详细说明和示例:
---
### **1. `map` 的核心特性**
- **同步执行**:转换操作(`Function`)会立即在当前线程执行,**不涉及异步操作**。
- **一对一转换**:输入一个值,输出一个转换后的值。
- **不改变 `Mono` 类型**:始终返回 `Mono<T>`,无法直接转换为 `Mono<R>` 以外的类型(如 `Flux`)。
---
### **2. 方法签名**
```java
Mono<R> map(Function<? super T, ? extends R> mapper)
```
- **输入**:`T` 类型的值(`Mono<T>` 中的元素)。
- **输出**:`R` 类型的转换结果(包装为 `Mono<R>`)。
---
### **3. 基础示例**
#### **示例 1:简单数据类型转换**
```java
Mono<Integer> numberMono = Mono.just(42);
Mono<String> stringMono = numberMono.map(num -> "The answer is " + num);
stringMono.subscribe(System.out::println); // 输出: The answer is 42
```
#### **示例 2:对象属性提取**
```java
record User(String name, int age) {}
Mono<User> userMono = Mono.just(new User("Alice", 30));
Mono<String> nameMono = userMono.map(User::name);
nameMono.subscribe(System.out::println); // 输出: Alice
```
---
### **4. 与 `flatMap` 的区别**
| 操作符 | 转换类型 | 是否支持异步 | 返回值 | 适用场景 |
|----------|---------------|--------------|-----------------|-----------------------|
| `map` | 同步 | ❌ 否 | `Mono<R>` | 简单计算、属性提取 |
| `flatMap`| 异步(嵌套) | ✅ 是 | `Mono<R>`/`Flux`| 调用返回 `Mono` 的服务 |
#### **对比代码**
```java
// 使用 map(同步)
Mono<String> result1 = Mono.just("user1")
.map(id -> id.toUpperCase()); // 同步操作
// 使用 flatMap(异步)
Mono<String> result2 = Mono.just("user1")
.flatMap(id -> fetchUserAsync(id)); // fetchUserAsync 返回 Mono<String>
```
---
### **5. 链式调用示例**
#### **场景:同步转换 + 异步操作组合**
```java
Mono.just("alice")
.map(String::toUpperCase) // 同步: 转大写
.flatMap(name -> saveToDatabase(name)) // 异步: 存数据库
.subscribe(
result -> System.out.println("Saved: " + result),
error -> System.err.println("Error: " + error)
);
```
---
### **6. 注意事项**
1. **不要阻塞 `map`**
如果转换逻辑涉及阻塞(如 IO、网络请求),必须改用 `flatMap` + `subscribeOn`:
```java
// 错误示范(阻塞主线程)
Mono.just("data").map(s -> blockingCall(s));
// 正确做法
Mono.just("data")
.flatMap(s -> Mono.fromCallable(() -> blockingCall(s))
.subscribeOn(Schedulers.boundedElastic()));
```
2. **空 `Mono` 处理**
如果 `Mono` 为空(如 `Mono.empty()`),`map` 不会执行转换逻辑:
```java
Mono.empty().map(Object::toString).subscribe(); // 无输出
```
3. **异常传播**
`map` 中的异常会直接终止流并触发 `onError`:
```java
Mono.just("abc")
.map(s -> { throw new RuntimeException("Oops"); })
.subscribe(
v -> {},
e -> System.out.println("Error: " + e) // 触发
);
```
---
### **7. 实际应用场景**
#### **场景 1:API 响应格式化**
```java
Mono<HttpResponse> apiResponse = fetchApi();
Mono<String> responseBody = apiResponse
.map(HttpResponse::body)
.map(body -> "Response: " + body);
```
#### **场景 2:数据预处理**
```java
Mono<RawData> rawDataMono = getRawData();
Mono<ProcessedData> processedMono = rawDataMono
.map(data -> normalize(data))
.map(data -> filterInvalid(data));
```
#### **场景 3:DTO 转换**
```java
Mono<UserEntity> entityMono = userRepository.findById(1);
Mono<UserDTO> dtoMono = entityMono.map(entity ->
new UserDTO(entity.getId(), entity.getName()));
```
---
### **总结**
- **`map`**:用于 **同步、非阻塞** 的简单转换。
- **`flatMap`**:用于 **异步** 操作(如调用返回 `Mono` 的服务)。
- **性能**:`map` 比 `flatMap` 更轻量,优先在同步场景使用。
通过合理选择 `map` 和 `flatMap`,可以高效构建响应式数据流。