当 Maybe 为空时终止流而不抛出异常

Terminate stream when Maybe is empty without throwing the exception

我有以下通过 REST 响应式调用的方法:

public Single<Result> generateValue(Request request) {
    return valueService.create(request.getArg())
        .switchIfEmpty(Maybe.fromAction(() -> new Result(new JsonObject()))) //empty result
        .toSingle()
        .flatMap(value -> repositoryService.persist(value))
        .map(obj -> new Result(obj.toJson()));
    }

我可以用 Maybe.error(new Exception()) 终止流,但调用方将收到我不想发送的错误响应。

当外部服务returns Maybe.empty()时,是否可以return Single<Result>(在中间终止流)而不恢复主流(来自toSingle() 行)?

更新

我尝试按照@akarnokd 的建议将flatMap + map 块放在switchIfEmpty 之前。首先,我将它们提取到单独的方法中:

private Single<Result> persistValue(Value value) {
        return repositoryService.persist(value))
                 .map(obj -> new Result(obj.toJson()));
    }

并在主管道中使用此方法:

public Single<Result> generateValue(Request request) {
    return valueService.create(request.getArg())
        .map(this::persistValue)
        .switchIfEmpty(Maybe.fromAction(() -> new Result(new JsonObject()))) //empty result
        .toSingle()
        .cast(Result.class);
    }

这一次,当 Maybe.empty() 被 return 编辑时,我得到:

Operation could not be performed as entity stream did not return any results: The MaybeSource is empty

java.util.NoSuchElementException: The MaybeSource is empty

因为它的空状态被传递给了persistValue方法。也许我没明白把 map 放在 Maybe.empty() 之后,然后放在 switchIfEmpty 之前的主要思想。

更新 2

模拟 class 复制和 运行 场景。 JsonObject 来自 gson 库。

public class MockExample {

    @Test
    public void testGenerateValue() {
        Handler handler = new Handler();

        handler.generateValue(new Request("testVal"))
                .subscribe();
    }

    class Handler {
        MockValueService valueService = new MockValueService();
        MockRepositoryService repositoryService = new MockRepositoryService();

        public Single<Result> generateValue(Request request) {
            return valueService.create(request.getArg())
                    .switchIfEmpty(Maybe.fromAction(() -> new Result(new JsonObject()))) //empty result
                    .toSingle()
                    .flatMap(value -> repositoryService.persist(value))
                    .map(obj -> new Result(obj.toJson()));
        }
    }

    class MockValueService {
        public Maybe<Value> create(String arg) {
            return Maybe.empty();
        }
    }

    class MockRepositoryService {
        public Single<Value> persist(Value value) {
            return Single.just(value);
        }
    }

    class Result {
        private JsonElement json;

        public Result(JsonElement json) {
            this.json = json;
        }

        public JsonElement getJson() {
            return json;
        }
    }

    class Request {
        private String arg;

        public Request(String arg) {
            this.arg = arg;
        }

        public String getArg() {
            return arg;
        }
    }

    class Value {
        private JsonObject original;

        public Value(JsonObject original) {
            this.original = original;
        }

        public JsonObject toJson() {
            return original;
        }
    }
}

通过模拟示例,我现在可以看到问题:

  1. .switchIfEmpty(Maybe.fromAction(() -> ...)) 为空,因为 Maybe.fromAction 永远不会产生成功值。你误以为是 fromCallable.
  2. persist returns Single 需要将 flatMapSingle 合并到序列中。
  3. 为确保类型保持正确,您必须在 switchIfEmpty 调用之前移动映射。

试试这个设置:

public Single<Result> generateValue(Request request) {
    return valueService.create(request.getArg())
            .flatMapSingleElement(value -> repositoryService.persist(value))
            .map(obj -> new Result(obj.toJson()))
            .switchIfEmpty(Maybe.fromCallable(() -> new Result(new JsonObject())))
            .toSingle()
            ;
}