Для меня это звучит как довольно распространенная проблема, с которой, как правило, сталкиваются младшие и средние разработчики: они либо не знают, либо не доверяют контрактам, в которых они участвуют, и защищают от нуля. Кроме того, при написании собственного кода они, как правило, полагаются на возврат значений 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 принимает необработанный пользовательский ввод и находит что-то, возможно, если вы реализуете интерфейс командной строки для чего-то. Теперь вы можете заключить договор, который возвращает ноль, если нет соответствующих действий. Это приводит к нулевой проверке, о которой вы говорите.
Альтернативное решение состоит в том, чтобы никогда не возвращать нуль и вместо этого использовать шаблон Null Object :
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);
}
}
}