You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何非阻塞将带Map属性的Mono<User>转换为Mono<VehiclesInfo>

问题场景

开发中定义如下DTO类:

public class User {
    int id;
    Map<String, Car> carsMap;

    public Map<String, Car> getCarsMap() {
        return carsMap;
    }
}

public class Car {
    String carName;

    public String getCarName() {
        return carName;
    }
}

// 接口返回对象
public class VehiclesInfo {
    List<String> vehicleName;

    public void setVehicleName(List<String> vehicleName) {
        this.vehicleName = vehicleName;
    }
}

通过userId查询数据库的返回值为Mono<User>类型,接口要求返回Mono<VehiclesInfo>类型,转换规则为:提取Mono<User>中carsMap存储的所有carName,组装为List赋值给VehiclesInfo的vehicleName属性,最终包装为Mono<VehiclesInfo>返回。
当前实现调用了blockOptional()触发阻塞操作,不符合响应式非阻塞要求,原有实现代码如下:

// userMono为数据库查询返回结果
Mono<User> userMono = getUserInfoById(userId);
Optional<User> userOptional = userMono.blockOptional();

if (userOptional.isPresent()) {
    User user1 = userOptional.get();
    Flux<Car> carFlux = Flux.fromIterable(user1.getCarsMap().keySet())
            .flatMap(i -> {
                Car c = new Car();
                c.setCarName(i);
                return Mono.just(c);
            });

    carFlux.subscribe(c -> System.out.println(c.getCarName()));
}
非阻塞实现方案

响应式编程规范中禁止在流处理链路中主动调用block()、blockOptional()这类阻塞方法,所有数据转换逻辑需要通过响应式操作符在流内部完成,最终由框架触发订阅,业务代码不需要手动调用subscribe()。

基础实现

import java.util.stream.Collectors;

Mono<User> userMono = getUserInfoById(userId);

Mono<VehiclesInfo> vehiclesInfoMono = userMono.map(user -> {
    VehiclesInfo vehiclesInfo = new VehiclesInfo();
    // 遍历carsMap的value,提取所有carName收集为List
    List<String> carNameList = user.getCarsMap()
            .values()
            .stream()
            .map(Car::getCarName)
            .collect(Collectors.toList());
    vehiclesInfo.setVehicleName(carNameList);
    return vehiclesInfo;
});

空安全兼容版本

如果需要兼容carsMap为null的场景,增加空判断避免空指针:

import java.util.Collections;
import java.util.Optional;
import java.util.stream.Collectors;

Mono<VehiclesInfo> safeVehiclesInfoMono = userMono.map(user -> {
    VehiclesInfo vehiclesInfo = new VehiclesInfo();
    List<String> carNameList = Optional.ofNullable(user.getCarsMap())
            .map(carMap -> carMap.values()
                    .stream()
                    .map(Car::getCarName)
                    .collect(Collectors.toList()))
            .orElse(Collections.emptyList());
    vehiclesInfo.setVehicleName(carNameList);
    return vehiclesInfo;
});

原有实现问题说明

  • 遍历carsMap.keySet()的逻辑错误:Map的key是String类型的索引键,carName实际存储在value位的Car对象属性中,直接遍历values()取值即可
  • 纯内存的集合转换不需要额外创建Flux处理,直接用JDK Stream完成转换性能更高,代码更简洁
  • 业务代码中不要手动订阅响应式流,WebFlux等响应式框架会在响应返回时自动触发订阅,手动提前订阅会导致流执行时机不可控,甚至出现请求上下文丢失的问题

内容的提问来源于stack exchange,提问作者AlwaysLearning

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:33:39