Когда обработка пустого указателя / ссылочного исключения предпочтительнее, чем выполнение нулевой проверки? - PullRequest
2 голосов
/ 07 декабря 2010

У меня странный вопрос, о котором я всегда думал, но никогда не мог найти практического применения.Я смотрю, чтобы найти достаточное обоснование для этого.

Когда обработка пустого указателя / ссылочного исключения предпочтительнее, чем проверка нуля?Если вообще.

Это относится к любому языку, который имеет дело с нулевыми указателями / ссылками, который имеет функции обработки исключений.

Мой обычный ответ на это будет выполнять нулевоепроверьте, прежде чем делать что-либо с указателем / ссылкой.Если не ноль, продолжайте как обычно и используйте это.Если ноль, обработайте ошибку или увеличьте ее.

т.е. (в C #)

string str = null;
if (str == null)
{
    // error!
}
else
{
    // do stuff
    int length = str.Length;
    // ...
}

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

string str = null;
int length = str.Length; // oops, NullReferenceException
// ...

Будучи исключением, мы, безусловно, могли бы поймать это, чтобы ничто не мешало нам сделать это (или есть?):

string str = null;
try
{
    int length = str.Length; // oops, NullReferenceException
    // ...
}
catch (NullReferenceException ex)
{
    // but that's ok, we can handle it now
}

Теперь я признаю, что это не таксамый чистый код, но он не менее рабочий код, и я бы не стал делать это нормально.Но есть ли шаблон дизайна или что-то, где это полезно?Возможно, это более полезно, чем предварительная проверка нуля заранее.

Единственные случаи, когда я могу себе представить, что это может быть полезно, - это многопоточная среда, в которой незащищенная общая переменная слишком рано устанавливается в ноль.Но как часто это происходит?Хороший код, который защищает переменные, не будет иметь этой проблемы.Или, возможно, если кто-то писал отладчик и хотел, чтобы исключение было выдано явно, только чтобы обернуть его или еще что-то.Может быть, непредвиденное повышение производительности или устранение необходимости в других вещах в коде?

Я мог бы ответить на некоторые из моих вопросов, но есть ли другой способ сделать это?Я не ищу «делать это только потому, что мы можем», как примеры или просто плохо написанный код, а для практического использования.Хотя со мной все будет в порядке, «в этом нет никакой практической пользы, сделайте проверку».

Ответы [ 5 ]

3 голосов
/ 07 декабря 2010

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

1 голос
/ 07 декабря 2010

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

Либо переменная иногда может быть нулевой (например, необязательный атрибут объекта), в этом случае мне нужно проверить на нулевое значение (obj.attr! = Null), или я ожидаю, что переменная не будет нулевой всегда (в этом случае ноль указывает на ошибку в другом месте кода). Если я пишу метод (скажем, isUpperCase), чей аргумент (String s) равен нулю, я явно проверяю на нулевое значение, а затем выкидываю исключение IllegalArgumentException.

То, что я никогда не делаю, - это молчаливое восстановление от нуля. Если метод должен возвращать количество символов в верхнем регистре в строке, а переданный аргумент равен нулю, я бы никогда не «скрыл» его, молча вернув 0 и, таким образом, замаскировав потенциальную ошибку.

1 голос
/ 07 декабря 2010

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

Это предпочтительно по двум причинам:

  1. Обычно вы используете одностроковую форму конструктора ArgumentNullException, передавая имя аргумента. Это дает очень полезную информацию во время отладки, так как теперь кодирующий знает, какой аргумент был нулевым. Если ваш источник им недоступен (или если трассировка исключений была отправлена ​​конечным пользователем без установленных отладочных символов), в противном случае невозможно будет сказать, что на самом деле произошло. С другими типами исключений вы также можете указать, какая переменная была нулевой, и это может быть очень полезной информацией.
  2. Поймание нулевого разыменования является одной из самых дорогих операций, которые может выполнять CLR, и это может оказать серьезное влияние на производительность, если ваш код выдает много исключений NullReferenceExceptions. Проверка на ничтожность и выполнение чего-то еще (даже исключения!) - более дешевая операция. (Аналогичный принцип заключается в том, что если вы объявляете блок catch с явным намерением перехватить NRE, вы делаете что-то не так в другом месте, и вам следует исправить это вместо использования try / catch. Отлов NRE не должен никогда быть неотъемлемой частью любого алгоритма. )

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

0 голосов
/ 28 апреля 2011

В Objective-C вы можете безопасно делать что-либо с nil, что вы можете делать с не-nil, и nil в конечном итоге становится noopЭто оказывается удивительно удобным.Гораздо меньше проверки нуля, а исключения зарезервированы для действительно исключительных обстоятельств.Или это будет считаться небрежным кодированием?

0 голосов
/ 07 декабря 2010

Лично (выполнение C ++), если только нет контракта STRONG, который гарантирует мне, что мои указатели не являются nullptr, я всегда проверяю их и возвращаю сообщение об ошибке или возвращаю молча, если это разрешено.

...