Значение по умолчанию для определения ошибки синтаксического анализа (строка -> двойное/любое числовое)

Какова наилучшая практика в Java для проверки недопустимых результатов синтаксического анализа при использовании «значения по умолчанию» вместо исключений?

(Устаревший) проект, над которым я работаю, имеет отказоустойчивый util-метод для разбора String в double, например:

//null checks, LOG output etc removed for readability
double parseDouble(String input, double defaultValue){ 
  try{    
    return Double.parseDouble(input)
  } catch (Exception e){
    return defaultValue;
  }
}

Теперь предыдущие разработчики всегда использовали значение по умолчанию, например returnedValue = parseDouble(someString, -99);, и проверку, например if (returnedValue == -99), для определения недопустимого результата синтаксического анализа. (Наконец) добавленный сервер SonarQube жалуется на эту проверку, используя == на double, и я хочу заменить эти проверки «правильной» проверкой.

Как лучше всего обращаться с такими случаями?

лично я бы использовал parseDouble(someString, Double.NaN); и соответственно чек if (Double.isNan(returnedValue). Это жизнеспособное решение?

РЕДАКТИРОВАТЬ: Я забыл упомянуть, что класс утилиты не редактируется (с моей точки зрения), и поэтому я ищу, как легко «исправить» существующий код. Также было бы неплохо добавить сторонние библиотеки, но (на данный момент) это также невозможно.

Возможно, это может вам помочь: google.github.io/guava/releases/19.0/api/docs/com/google/com‌​mon/… С помощью этой библиотеки вы можете проверить, является ли двойное значение нулевым (проще проверить)

MPhil 10.05.2019 11:25

Или вы можете изменить свой собственный код. Вы можете вернуть null вместо defaultValue (вы должны изменить возвращаемый параметр на Double). Поэтому легко проверить, не равно ли значение Double значение null и синтаксический анализ прошел успешно.

MPhil 10.05.2019 11:31

@MPhil Это невозможно с моей точки зрения. Это служебный класс "для всей компании", и я не могу ничего там изменить самостоятельно. Тем не менее, вы сделали правильный вывод, и я бы тоже это реализовал.

Coronero 10.05.2019 11:38

Да я вижу. Тогда я лично выбрал бы решение if (Double.isNan(returnedValue)) . Я думаю, что это лучшее в этом случае.

MPhil 10.05.2019 11:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
484
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В старые времена я также использовал бы NAN, POSITIVE_INFINITY, MAX_VALUE или любой другой, который не используется. Теперь я бы использовал необязательный класс. Использование целых чисел ненадежно из-за преобразования, а использование нуля — это ошибка Хоара на один миллиард долларов: означает ли нуль ошибку, не инициализированную, не заданную? Была ли входная строка нулевой или она была проанализирована и не была допустимым двойным представлением?

По сути, вам не нужен метод, который возвращает вам значение по умолчанию, когда произошла ошибка синтаксического анализа или нулевой ввод, или пользователь ввел значение по умолчанию. Вам нужен метод, который возвращает информацию о том, была ли ошибка или нет, а если нет, то проанализированное значение. Чтобы сделать ваш код более читабельным и понятным, я бы написал именно такой метод и использовал его везде, где это уместно (вместо того, чтобы везде копировать и вставлять обходные пути). Если вы не можете поместить его в существующий служебный класс, создайте собственный дополнительный служебный класс. Если вы используете Java 8, вы можете использовать дополнительный класс. Если нет, то запрограммируйте свой собственный вариант (или возьмите его из какой-нибудь библиотеки). Вот служебный метод:

Optional<Double> parseDouble(String input) { 
  try {    
    return Optional.of(Double.parseDouble(input));
  } catch (Exception e) {
    return Optional.empty();
  }
}

Вот как это использовать:

String input = ...;
Optional<Double> parsedInput = parseDouble(input);
if (! parsedInput.isPresent()) {
    // print out warning and retry input or whatever
}
double convertedInput = parsedInput.value();

Примечание:

SonarQube также будет критиковать обнаружение общего «Исключения». Вместо этого вы должны поймать NumberFormatException и NullPointerException. Когда вызывающему абоненту необходимо знать точную причину, вы можете добавить метод getEmptyReason() в свой необязательный (или производный класс) и сохранить там причину исключения. Но я предполагаю, что в вашем случае вы хотите использовать значение по умолчанию, если входная строка не была задана (пустая или нулевая), и хотите выполнить обработку ошибок, если значение было задано, но не поддается анализу. В этом случае вы можете использовать:

Optional<Double> parseDouble(String input, double defaultValue) { 
  if (input == null || input.trim().length == 0) {
    return Optional.of(defaultValue);
  }
  try {    
    return Optional.of(Double.parseDouble(input));
  } catch (NumberFormatException e) {
    return Optional.empty();
  }
}

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