Нульовий вказівник
Нульовий (порожній) вказівник (рідше — покажчик) — вказівник, який нікуди не вказує. Використовується для того, щоб показати, що дана змінна-вказівник ні на що не посилається. У різних мовах програмування представлений різними константами, наприклад:
- У машинних кодах: 0
- У мовах Pascal, Clipper, Modula 2, Ruby, Lua : nil
- У C-подібних мовах: NULL
- У мовах Java та C#: null
- У мові Icon: &null
- У мові Python: None
- У мові Visual Basic: Nothing
Тоні Гоар, який винайшов нульовий вказівник у 1965 році, вважає це помилкою, яка імовірно коштувала мільярди доларів, оскільки спроба розіменування нульового вказівника зазвичай приводить до збою й припинення роботи програми[1].
Особливості використання в різних мовах
C та C++
Макрос NULL
визначено у файлі <stddef.h>
.
ANSI C гарантує, що значення NULL еквівалентне 0, тому записи
int *a, *b;
a = NULL;
b = 0;
еквівалентні — вказівники a та b отримають однакове значення.
На відміну від C в Паскалі, який є дуже суворим щодо типів, Nil в жодному випадку не еквівалентний числу 0.
Java
Мова програмування Java використовує null
для позначення порожнього посилання. Також мова визначає так званий тип даних null. При спробі використання null
замість реального об'єкта віртуальна машина створює виняткову подію типу java.lang.NullPointerException
. Зокрема, ця подія виникає при:
- виклику динамічного метода об'єкта
null
. - доступі або зміні поля об'єкта
null
. - обчисленні довжини об'єкта
null
наче він є масивом. - доступі або зміні комірок об'єкта
null
наче він є масивом. - створенні виняткової ситуації з об'єктом
null
замість об'єкта типуThrowable
.
Додатки також можуть створювати виняткові ситуації типу NullPointerException
за інших невірних використаннях об'єктів типу null
[2].
З огляду на численні проблеми, спричинені неправильною обробкою об'єктів null
та досвіду використання деяких інших мов програмування в бібліотеці стандартних класів Java SE 8 версії був доданий контейнер Optional<T>
. Об'єкти даного класу можуть містити значення типу null
. Якщо контейнер містить непорожнє значення, тоді метод isPresent()
поверне true
а метод get()
поверне це значення. Також цей контейнер пропонує низку додаткових методів, поведінка яких залежить від наявності непорожнього значення. Наприклад, метод orElse()
повертає значення за замовченням при відсутності даних в контейнері, ifPresent()
виконує блок коду за умови наявності даних в контейнері[3].
Наприклад, якщо комп'ютер не має звукової карти і метод getSoundcard()
повертає null
, то при виконанні наступного коду:
String version = computer.getSoundcard().getUSB().getVersion();
виникне виняткова ситуація типу NullPointerException
при спробі викликати метод getUSB()
. Проте, засобами контейнеру Optional<T>
цей код може бути перетворений на безпечніший (після відповідного рефакторингу залучених типів даних):
String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
унаслідок виконання якого змінна version
матиме значення «UNKNOWN» за відсутності звукової карти[4].
Примітки
- Tony Hoare. Null References: The Billion Dollar Mistake. Архів оригіналу за 19 січня 2009. Процитовано 23 жовтня 2010.
- Class NullPointerException. Java™ Platform Standard Ed. 8. API Specification. Oracle. 2016.
- Class Optional<T>. Java™ Platform Standard Ed. 8. API Specification. Oracle. 2016.
- Raoul-Gabriel Urma (March 2014). Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!. Oracle Technology Network.
Див. також
Посилання
- CWE-476: NULL Pointer Dereference
- Quora: What actually happens when dereferencing a NULL pointer?