Webflux控制流场景:应使用then还是flatMap?
then() vs flatMap() for Reactor Existence Check Flow Great question! Let's break down which operator makes sense for your WebFlux control flow scenario, where you need to validate an object exists before running business logic (and throw an error if it doesn't).
First, let's recap your core requirement:
Check if an object exists via
repository.exists(Mono<IdType>). If it does, runsomeBusinessLogic(). If not, throw aDoesntExistException.
Understanding then() for Your Scenario
Your current code uses then() after the existence check, and this is actually the more semantically correct choice here. Here's why:
then()ignores all upstream elements and only reacts to the completion signal of the preceding Mono. It says: "Once the previous step finishes successfully (without errors), run the next Mono."- In your flow, the existence check is a pure validation step—you don't need to pass any data (like the
IdTypeor theBooleanresult fromexists()) to your business logic. You just need to ensure the validation passes (i.e., the object exists, so no exception is thrown).
Your code structure is clean because it separates the validation phase from the business logic phase:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){ return id.flatMap(repository::exists) // Check if object exists .flatMap(e -> e ? Mono.empty() : Mono.error(new DoesntExistException())) // Validate existence, throw if missing .then( // Run business logic ONLY after validation completes successfully Mono.fromCallable(this::someBusinessLogic) ); }
When Would flatMap() Be Better?
flatMap() is designed to transform upstream elements into new Publishers. It's useful when you need to use the output of the previous step to drive the next part of your flow.
For your scenario, a flatMap-based approach would look something like this:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){ return id.flatMap(repository::exists) .flatMap(exists -> { if (exists) { return Mono.fromCallable(this::someBusinessLogic); // Use existence result to trigger logic } else { return Mono.error(new DoesntExistException()); } }) .then(); // Convert to Mono<Void> if needed }
But this is less ideal here because:
- You're not actually using the
existsBoolean value for anything beyond the basic check—you don't need to pass it to the business logic. - The code mixes validation and business logic in the same
flatMap()block, making it slightly less readable than separating them withthen().
Final Recommendation
Use then() for your specific scenario:
- It makes your code's intent clearer: "First validate the object exists, then run the business logic."
- It keeps validation and business logic separate, which improves maintainability.
- It's more idiomatic for Reactor flows where you don't need to propagate upstream data to the next step.
Only use flatMap() if you later need to leverage the output of the existence check (or the original IdType) within your business logic.
内容的提问来源于stack exchange,提问作者Filip Malczak

