首页 > 解决方案 > 当 Maybe 为空时终止流而不抛出异常

问题描述

我有以下通过 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())但调用方会收到我不想发送的错误响应。

当外部服务返回时是否可以返回Single<Result>(在中间终止流)Maybe.empty(),而不恢复主流(从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()返回时,我得到:

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方法。也许我没有抓住把mapafter Maybe.empty()before的主要想法switchIfEmpty

更新 2

模拟类来复制和运行场景。JsonObject来自 gson lib。

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;
        }
    }
}

标签: javarx-java2

解决方案


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

  1. .switchIfEmpty(Maybe.fromAction(() -> ...))为空,因为Maybe.fromAction从不产生成功值。你把它误认为fromCallable.
  2. persist返回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()
            ;
}

推荐阅读