Вызов Optional # isPresent () в одной строке сообщается как не вызываемый

Я запускаю SonarQube, чтобы проверить свой код, и обнаружил случай, в котором я не понимаю сообщенную ошибку.

Мой код:

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

Метод asInteger возвращает Optional<Integer>.

Ошибка, которую я получаю от sonarqube, Call "Optional#isPresent()" before accessing the value. в обратной линии.

Я понимаю, что код в порядке, так как вторая часть if не будет выполняться, если первая неверна. Я знаю, что это можно решить с помощью .filter(..).isPresent(), но мне больше нравится такой способ.

Есть идеи, почему это произошло?

Я бы сказал, это просто потому, что эти инструменты проверки кода не всегда работают идеально, а некоторые ошибки являются просто ложными срабатываниями. ЕСЛИ вы перепишите его как if (...), я уверен, что об ошибке больше не будет

UninformedUser 06.11.2018 21:42

Что, если второй вызов id.asInteger() вернет пустой Optional?

tsolakp 06.11.2018 21:44

А как насчет return id.asInteger().orElse(-1) >= BASE_ID;?

Holger 07.11.2018 08:12
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
16
3
3 517
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете написать это как одно заявление, кстати:

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

но жалобы эхолота вызваны тем, что в данном случае это ложное срабатывание.

Да, я знаю, что могу решить эту проблему с помощью разных методов, таких как тот, который я написал в самом вопросе: .filter(..).isPresent(), но мне больше нравится другой способ, и я хочу понять, почему это может происходить. Я имею в виду, вызывается isPresent () ...

Pablo Matias Gomez 06.11.2018 21:44

Но SonarQube не может знать, возвращает ли каждый вызов asInteger () другое значение. Итак, во второй раз, когда вы вызываете get (), это может быть пустой Необязательный

EduSanCon 06.11.2018 21:47

Это не ложное срабатывание - сонар совершенно прав, указывая на это как на потенциальную проблему.

Hulk 07.11.2018 08:57
Ответ принят как подходящий

Sonarqube не может гарантировать, что два вызова id.asInteger() вернут один и тот же объект, например поскольку многопоточность могла изменить значение id между двумя вызовами, поэтому правильно указывается, что наличие не было должным образом протестировано.

Измените код, чтобы сначала назначить его локальной переменной, чтобы гарантировать, что isPresent() и get() вызываются для одного и того же объекта:

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

Многопоточность даже не требуется: два вызова одного и того же метода не гарантируют возврата одного и того же, и я не уверен, что Sonar может гарантировать, что asInteger () идемпотентен.

JB Nizet 06.11.2018 21:46

@Andreas отличная точка, 1+, но я бы полностью написал это как одно утверждение, хотя

Eugene 06.11.2018 21:47

@JBNizet Sonar никогда не может гарантировать какие-либо свойства метода в другом классе, так как он даже не может гарантировать, что реализация будет такой же во время выполнения. Единственными исключениями могут быть хорошо известные (JDK) методы с точно определенным контрактом или формальные контракты, выраженные в виде аннотаций.

Holger 07.11.2018 08:15

При работе с Optionals вам следует по возможности избегать .isPresent и .get. Использование этих методов не безопаснее, чем использование нулей, и противоречит функциональному духу. Необязательные параметры предназначены для функционального программирования и для типизированной альтернативы нулевых проверок.

SonarQube имеет ограниченные возможности анализа. Обычно он не может исключить все виды ложных срабатываний. Этот случай не является проблемой, потому что не рекомендуется использовать Optionals таким образом.

Не обязательно. Например, как бы вы не использовали isPresent, когда вы хотите предпринять какое-то действие, когда значение отсутствует.

tsolakp 06.11.2018 21:59

@tsolakp Начиная с Java 9 yourOptional.ifPresentOrElse(dummy, this::someAction);. Однако ваша точка зрения верна, это один из редкий (и, возможно, даже востребованных?) Случаев, когда можно защищать использование isPresent().

Ole V.V. 11.11.2018 13:55

Да, я не собирался говорить «вы не должны использовать isPresent», но «в большинстве случаев было бы лучше избегать этого, если это возможно».

Donat 11.11.2018 14:26

Чтобы избежать этой проблемы, я использую iterator (). Next (), он имеет те же функции, что и .get, но без проблемы с isPresent ()!

Другие вопросы по теме