Calling Optional#isPresent() in single line is reported as not called

Viewed 4513

I run SonarQube to check my code and I found a case which I don't understand the reported error.

My code is:

private static final int BASE_ID = 100_000_000;
private boolean isValidId(Id id) {
    return id.asInteger().isPresent() && id.asInteger().get() >= BASE_ID;
}

The method asInteger returns Optional<Integer>

The error that I am getting from sonarqube is Call "Optional#isPresent()" before accessing the value. in the return line.

I understand that the code is ok as the second part of the if won’t get executed if the first one is false. I know that this can be solved with a .filter(..).isPresent() but I like it more this way.

Any ideas why would this happen?

4 Answers

Sonarqube cannot guarantee that the two calls to id.asInteger() returns the same object, e.g. because multi-threading might have changed the value of id between the two calls, so it is correctly stating that the presence hasn't been adequately tested.

Change code to assign to a local variable first, to ensure that isPresent() and get() are called on the same object:

private boolean isValidId(Id id) {
    Optional<Integer> idAsInteger = id.asInteger();
    return idAsInteger.isPresent() && idAsInteger.get() >= BASE_ID;
}

You can write that as a single statement btw:

return id.asInteger()
         .map(x -> x >= BASE_ID)
         .orElse(false)

but sonar complaining is because well it's a false positive in this case.

When working with Optionals you should avoid .isPresent and .get as much as possible. The use of these methods in not safer than using nulls and is against the functional spirit. Optionals are made for functional programming and for a typesafe alternative of null checks.

SonarQube has only limiteds capabilities with its analysis. It usually cannot exclude all kinds of false positives. This case is not really a problem because it is not recommended to use Optionals this way.

To avoid this problem I use iterator().next() it has the same functionality that .get but it cames without the isPresent() issue!

Related