如何用不同签名方法链式调用实现基于Vavr Either的业务流程?
优雅实现基于Vavr Either的链式业务流程处理
你的核心问题是错误地直接执行了方法而非传递函数引用,同时没有正确利用flatMap(对应C#的Bind)来串联返回Either的操作。下面是符合最佳实践的实现方案:
关键优化点
- 用
flatMap替代map串联流程:因为每个步骤返回Either<ErrorResult, T>,flatMap会自动处理错误短路(一旦返回Left,后续步骤直接跳过),这就是Java中C#Bind的等价实现。 - 捕获
correlationId避免冗余传递:提前从Context中提取correlationId,通过lambda捕获传入各步骤,不用将其设为类字段。 - 聚焦核心数据:链式调用从业务输入
WhateverEntityInput开始,而非整个Context,避免冗余数据传递。
修正后的完整代码
import io.vavr.control.Either; import java.util.UUID; public class VavrPractice { public static void handle(Context context) { UUID correlationId = context.getCorrelationId(); // 链式执行流程,自动处理错误短路 Either<ErrorResult, WhateverEntityResult> result = Either.right(context.getWhateverEntityInput()) .flatMap(input -> validateInput(input, correlationId)) .flatMap(validatedInput -> mapToWhateverEntity(validatedInput, correlationId)) .flatMap(entity -> saveToDatabase(entity, correlationId)) .flatMap(savedEntity -> mapToWhateverEntityResult(savedEntity, correlationId)); // 统一处理最终结果:成功/失败分支 result.fold( error -> logError(error), success -> processSuccess(success) ); } // 验证输入:失败返回带correlationId的ErrorResult,成功返回原输入 private static Either<ErrorResult, WhateverEntityInput> validateInput(WhateverEntityInput input, UUID correlationId) { if (input == null || input.getContent().isEmpty()) { return Either.left(new ErrorResult(correlationId, "输入内容不能为空")); } return Either.right(input); } // 映射为实体:失败返回错误,成功返回转换后的实体 private static Either<ErrorResult, WhateverEntity> mapToWhateverEntity(WhateverEntityInput input, UUID correlationId) { try { return Either.right(new WhateverEntity(input.getContent())); } catch (IllegalArgumentException e) { return Either.left(new ErrorResult(correlationId, "实体映射失败:" + e.getMessage())); } } // 存储实体:生成ID后返回带ID的实体,失败返回错误 private static Either<ErrorResult, WhateverEntity> saveToDatabase(WhateverEntity entity, UUID correlationId) { try { UUID generatedId = UUID.randomUUID(); // 模拟存储生成ID entity.setId(generatedId); // 执行数据库存储操作 return Either.right(entity); } catch (Exception e) { return Either.left(new ErrorResult(correlationId, "存储失败:" + e.getMessage())); } } // 映射为结果:将带ID的实体转换为输出结果 private static Either<ErrorResult, WhateverEntityResult> mapToWhateverEntityResult(WhateverEntity entity, UUID correlationId) { try { return Either.right(new WhateverEntityResult(entity.getId(), entity.getContent())); } catch (Exception e) { return Either.left(new ErrorResult(correlationId, "结果映射失败:" + e.getMessage())); } } // 错误处理逻辑 private static void logError(ErrorResult error) { System.err.printf("[Correlation ID: %s] 流程失败:%s%n", error.getCorrelationId(), error.getMessage()); } // 成功处理逻辑 private static void processSuccess(WhateverEntityResult result) { System.out.printf("流程完成,生成实体ID:%s%n", result.getEntityId()); } // 辅助实体类定义 static class Context { private WhateverEntityInput whateverEntityInput; private UUID correlationId; // 构造器、getter省略 public WhateverEntityInput getWhateverEntityInput() { return whateverEntityInput; } public UUID getCorrelationId() { return correlationId; } } static class WhateverEntityInput { private String content; // 构造器、getter省略 public String getContent() { return content; } } static class WhateverEntity { private UUID id; private String content; public WhateverEntity(String content) { this.content = content; } // setter、getter省略 public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getContent() { return content; } } static class WhateverEntityResult { private UUID entityId; private String content; public WhateverEntityResult(UUID entityId, String content) { this.entityId = entityId; this.content = content; } // getter省略 public UUID getEntityId() { return entityId; } } static class ErrorResult { private UUID correlationId; private String message; public ErrorResult(UUID correlationId, String message) { this.correlationId = correlationId; this.message = message; } // getter省略 public UUID getCorrelationId() { return correlationId; } public String getMessage() { return message; } } }
核心逻辑说明
- flatMap的作用:每个步骤返回
Either,flatMap会自动解包Right值传递给下一个步骤;如果某个步骤返回Left,后续链式调用会直接短路,不会执行,错误信息会被保留到最终的Either中。 - lambda捕获correlationId:提前从
Context提取correlationId,在每个步骤的lambda中直接引用,既保持方法无状态,又避免重复从Context取值。 - 结果处理:用
fold方法统一处理成功(Right分支)和失败(Left分支),这是Vavr处理Either结果的标准方式。
内容的提问来源于stack exchange,提问作者AndrasCsanyi
相关产品推荐
相关产品推荐

