Home > OS >  How to get Different Optional type of Object from CompletableFuture
How to get Different Optional type of Object from CompletableFuture

Time:02-23

I have one code snippet, which is calling 2 different services based on some a if condition. And both the services return CompletableFuture<Optional<SomeObject>>. Following is the code logic looks like

if(someCondition){
  CompletableFuture<Optional<SomeObjectType1>> = service1.call();
}else{
  CompletableFuture<Optional<SomeObjectType2>> = service2.call();
}

And both SomeObjectType1 and SomeObjectType2 have a String inside it, which is of my interest. My current code looks like this:

private ContentWrapper getContentWrapper(input1, input2, ....) {
    String content = null;
    if (some_condition is true) {
        List<Object_Type_1> list = service1.fetchTheCompletableFuture(..... inputs...)
                .join()
                .map(ListOutput::getList)
                .orElse(null);
        if (CollectionUtils.isNotEmpty(list)) {
            content = list.get(0).getContent();
        }
    } else {
        content = service2
                .fetchTheCompletableFuture(..... inputs...)
                .join()
                .map(RenderedContent::getContent)
                .orElse(null);
    }
    return content != null ? new ContentWrapper(content) : null;
}

Now my question is, can this if-else clause be removed or make it more clear by using lambdas. I am new in lambdas and does not have very good idea on this.

CodePudding user response:

I am not sure whether the code below even compiles due to the vagueness.

private ContentWrapper getContentWrapper(input1, input2, ....) {
    Optional<RenderedContent> content = some_condition
        ? service1
                .fetchTheCompletableFuture(..... inputs...)
                .join()
                .map(ListOutput::getList)
                .stream()
                .findFirst()
        : service2
                .fetchTheCompletableFuture(..... inputs...)
                .join();
    }
    return content
                .map(RenderedContent::getContent)
                .map(ContentWrapper::new).orElse(null);
}
  • The first service seems to yield a list of RenderedContent of which to take the first if there is one.
  • The second service may yield a Rendered content immediately.

So you can join the if-else to an Optional<RenderedContent>. The map(RenderedContent::getContent) will yield Optional.empty() if it was empty to begin with. Otherwise getContent is called and wrapped in an Optional. If present new ContentWrapper(...) might be called.

Notice much may fail, like getContent returning null (though there is an Optional.ofNullable.

Nevertheless Streams may be very expressive.

I would avoid using null in favor of Optional as that plays better together.

  • Related