Каково правильное сообщение об ошибке для предоставления Google Guava Preconditions. * Методов?

Например, при использовании Preconditions.checkArgument, является ли сообщение об ошибке предполагаемым случаем передачи или неудачным случаем проверки?

import static com.google.common.base.Preconditions.*;

void doStuff(int a, int b) {
  checkArgument(a == b, "a == b");
  // OR
  checkArgument(a == b, "a != b");
}

Ответ 1

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

Документация приведена в следующем примере:

Это позволяет создавать такие конструкции, как

 if (count <= 0) {
   throw new IllegalArgumentException("must be positive: " + count);
 }

чтобы заменить его более компактным

 checkArgument(count > 0, "must be positive: %s", count);

Следует отметить две вещи:

  • В этом примере явно указано требование, а не факт
    • "что-то должно быть правильно", вместо "что-то не так"
  • Инвертируя условие проверки, вся конструкция читается более естественно

Следуя этому примеру, лучшим сообщением будет следующее:

checkArgument(a == b, "a must be equal to b"); // natural!

Вы даже можете сделать еще один шаг и зафиксировать значения a и b в сообщении об исключении (см. "Эффективное Java 2-е издание", пункт 63: включить подробные сообщения о сбое):

checkArgument(a == b, "a must be equal to b; instead %s != %s", a, b);

Альтернатива высказывания фактов менее естественно читать в коде:

checkArgument(a == b, "a != b");              // awkward!
checkArgument(a == b, "a is not equal to b"); // awkward!

Обратите внимание, как неудобно читать в Java-коде одно булевское выражение, за которым следует строка, которая противоречит этому выражению.

Другой недостаток, связанный с фактами, заключается в том, что для сложных предварительных условий он потенциально менее информативен, поскольку пользователь может уже знать об этом, но не то, что нарушает фактические требования.

Связанные вопросы

Ответ 2

В документации приводятся примеры, которые делают это очень понятным, используя слова вместо символов:

checkArgument(count > 0, "must be positive: %s", count);

Учитывая, что это в основном просто сообщения об исключениях в журналах (или отладочных сеансах), сделайте все, что, по вашему мнению, станет ясным для всех, кто смотрит на проблему, или кто-нибудь читает код, чтобы понять предварительное условие.

Например, вы можете переписать вышеприведенное как:

checkArgument(count > 0, "count must be positive; was actually %s", count);

Ответ 3

Лично для чего-то подобного я думаю, что напишу

checkArgument(a == b, "a (%s) must equal b (%s)", a, b);

Ответ 4

Часто (в большинстве случаев) вы можете просто использовать метод checkArgument() без параметра сообщения об ошибке, то есть не поставлять сообщение об ошибке вообще.

Чтобы сделать хорошее сообщение об ошибке, нужно понять, кто будет читать это сообщение. Это не конечный пользователь; если предварительное условие выходит из строя, оно скорее всего указывает на ошибку в коде. Текст может объяснить неудачное предварительное условие, но в большинстве случаев он не нужен конечному пользователю, он должен быть подсказкой для программиста. Большую часть времени сообщение само по себе также не имеет смысла без stacktrace и исходного кода. Фактически, в большинстве случаев, stacktrace и исходный код - это именно то, что программисту нужно исправить ошибку, сообщение об ошибке не помогает. Если предварительное условие не является очевидным, комментарий рядом с ним является идеальным способом документировать его.

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

Есть некоторые случаи, когда сообщение об ошибке может быть полезно, например, сообщение может содержать фактические значения переменных, но из нашего опыта это не очень часто, и в этих случаях вы можете использовать это сообщение.

Аналогичные аргументы применяются также в методах assert в JUnit; всегда предоставление сообщения об ошибке не является хорошей идеей.

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

Ответ 5

Как polygenelubricants указали:

Для проверки предварительных условий указание требования в подробном сообщении об исключении более информативно, чем просто указание фактов.

В то время как вы, безусловно, можете сделать это с предусловиями Guava, API требований (который я создал) позволяет вам добиться большей производительности без каких-либо усилий ваша часть.

Предпосылки Guava

String a = "foosball";
String b = "ballroom";
Preconditions.checkArgument(a == b, "a == b");

дает вам следующее:

java.lang.IllegalArgumentException: a == b
    at com.google.common.base.Preconditions.checkArgument(Preconditions.java:122)
    at Main.main(Main.java:142)

API требований

String a = "foosball";
String b = "ballroom";
requireThat(a, "a").isEqualTo(b, "b")

дает вам следующее:

output

Тот же ввод, лучший вывод.

(Если ваш терминал не поддерживает цвета, вы получите текстовый diff вместо этого)