Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional<String> map function returns null

Can someone help me with the below piece of code? I would like an equivalent using Optional functions.

public String getMyRequiredValue(Optional<String> value) {
    if(value.isPresent()) {
        Optional<String> optionVal = getAnotherValue(value.get());
        if(optionVal.isPresent()) {
            return optionVal.get();
        } else {
            return null;
        }
    } else {
        return "Random";
    }
}

public Optional<String> getAnotherValue(String value) { ... }

Just a note I tried this, but it does not work

return value.map(lang -> getAnotherValue(lang).orElse(null)).orElse("Random");

The thing that is not working is - when the value is present and getAnotherValue returns Optional.empty() I want the original function to return null. It is returning "Random" right now.

My assumption is since the map method returns null it gets replaced by "Random".

Note that the original code was written by someone else. Since, it has a lot of dependencies, I cannot change the input/output parameters. :(

like image 548
meso Avatar asked Aug 31 '18 20:08

meso


People also ask

Can Optional map return null?

The class invariant is that an Optional can never hold a null value, so either the map should fail or it should return an empty Optional .

What does Optional map return?

The method Optional. map(Function) applies the given function to the optional value if it is present and returns an optional with the result or empty optional.

Which of the following test Optional method returns true if the Optional refers to null?

ofNullable. Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional .

What does map do in Optional?

Optional. map() method is to convert Optional<T> to Optional<U> . Following are few facts about map() operation. If the value of T is null, .


1 Answers

The solution originally suggested by @Andreas in the comments:

public String getMyRequiredValue(Optional<String> value) {
    return value.isPresent() ? getAnotherValue(value.get()).orElse(null) : "Random";
}

The solution I came up with first. It breaks the rule that suggests we always need to check isPresent() before calling get() and introduces exception handling. So it's better to stick to the first idea.

public String getMyRequiredValue2(Optional<String> value) {
    try {
        return getAnotherValue(value.get()).orElse(null);
    } catch (NoSuchElementException e) {
        return "Random";
    }
}

I've seen you were trying to utilise map and flatMap. If they result in an Optional.empty(), it's unclear where null came from: it could be either value or getAnotherValue(value.get()).

We could track that by saving the value coming from value.get() into a Holder<String>:

public String getMyRequiredValue3(Optional<String> value) {
    final Holder<String> holder = new Holder<>();
    return value.flatMap(i -> getAnotherValue(holder.value = i))
                .orElse(holder.value == null ? "Random" : null);
}

Again, the first approach still beats this.


EDIT: As pointed out by @Holder, we don't need a Holder from the preceding example. Instead we can check value.isPresent():

public String getMyRequiredValue4(Optional<String> value) {
    return value.flatMap(this::getAnotherValue) 
                .orElse(value.isPresent() ? null : "Random");
}
like image 195
Andrew Tobilko Avatar answered Oct 30 '22 13:10

Andrew Tobilko