Для меня это звучит как довольно распространенная проблема, с которой, как правило, сталкиваются разработчики младших и средних уровней: они либо не знают, либо не доверяют контрактам, в которых они участвуют, и защищаются от нуля. Кроме того, при написании собственного кода они, как правило, полагаются на возврат значений NULL для указания чего-либо, что требует от вызывающей стороны проверки на наличие значений NULL.
Другими словами, в двух случаях возникает проверка нуля:
Где ноль - действительный ответ по условиям контракта; и
Где это не правильный ответ.
(2) легко. Либо используйте assert
операторы (утверждения), либо разрешите ошибку (например, NullPointerException ). Утверждения - это сильно недоиспользуемая функция Java, которая была добавлена в 1.4. Синтаксис:
assert <condition>
или
assert <condition> : <object>
, где <condition>
- логическое выражение, а <object>
- объект, чей вывод метода toString()
будет включен в ошибку.
Оператор assert
выдает Error
(AssertionError
), если условие не выполняется. По умолчанию Java игнорирует утверждения. Вы можете включить утверждения, передав опцию -ea
в JVM. Вы можете включать и отключать утверждения для отдельных классов и пакетов. Это означает, что вы можете проверять код с помощью утверждений при разработке и тестировании и отключать их в производственной среде, хотя мое тестирование показало, что утверждения не оказывают никакого влияния на производительность.
Не использовать утверждения в этом случае - это нормально, потому что код просто потерпит неудачу, что произойдет, если вы используете утверждения. Единственное отличие состоит в том, что с утверждениями это может произойти раньше, более значимым образом и, возможно, с дополнительной информацией, которая может помочь вам выяснить, почему это произошло, если вы этого не ожидали.
(1) немного сложнее. Если у вас нет контроля над кодом, который вы вызываете, вы застряли. Если нулевой является действительным ответом, вы должны проверить его.
Однако, если вы управляете кодом (и это часто бывает), то это другая история. Избегайте использования нулей в качестве ответа. С методами, которые возвращают коллекции, это легко: возвращать пустые коллекции (или массивы) вместо нулей почти все время.
С не-коллекциями это может быть сложнее. Рассмотрим это в качестве примера: если у вас есть эти интерфейсы:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
где Parser берет необработанный пользовательский ввод и находит что-то, возможно, если вы реализуете интерфейс командной строки для чего-то. Теперь вы можете заключить договор, который возвращает ноль, если нет соответствующих действий. Это приводит к нулевой проверке, о которой вы говорите.
Альтернативное решение - никогда не возвращать нуль и вместо этого использовать шаблон Нулевой объект :
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
Сравните:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
до
ParserFactory.getParser().findAction(someInput).doSomething();
, который намного лучше, потому что это приводит к более краткому коду.
Тем не менее, возможно, для метода findAction () вполне уместно выдать исключение со значимым сообщением об ошибке, особенно в том случае, когда вы полагаетесь на пользовательский ввод. Было бы гораздо лучше, чтобы метод findAction выдавал исключение, чем вызывающий метод взорвался простой NullPointerException без объяснения причин.
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
Или, если вы считаете, что механизм try / catch слишком уродлив, вместо «Ничего не делать», ваше действие по умолчанию должно обеспечивать обратную связь с пользователем.
public Action findAction(final String userInput) {
/* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}