Null
Null (от лат. nullus — никакой, ничто) — в программировании и информатике специальное значение, обозначающее отсутствие какого-либо объекта, данных или ссылки. Null указывает на то, что переменная, указатель или поле не содержит никакого осмысленного значения, находится в неопределённом состоянии или не инициализировано. В разных языках программирования null может быть представлен как отдельный тип данных (например, в Java), как специальное значение ссылочного типа (в C#) или как константа (в C/C++). Концепция null тесно связана с понятием «пустого» значения, но не тождественна ему: в отличие от пустой строки, нуля или пустого списка, null означает именно отсутствие ссылки на объект, а не наличие объекта с нулевым содержимым.
История
Концепция null была введена Тони Хоаром в 1965 году при разработке языка ALGOL W. Хоар ввёл нулевые ссылки (null references) для обозначения отсутствия значения в ссылочных типах данных. Позднее он назвал это изобретение «ошибкой на миллиард долларов», имея в виду огромное количество программных ошибок и уязвимостей, вызванных неправильной обработкой null (так называемые ошибки разыменования нулевого указателя — null pointer dereference). Несмотря на критику, null стал неотъемлемой частью большинства языков программирования, включая C, C++, Java, C#, JavaScript, Python и многие другие.
В 1970-х годах null был реализован в языке C как макрос NULL, определённый как (void*)0 или просто 0. В C++ null-указатель также представляется целочисленной константой 0, а с появлением стандарта C++11 — ключевым словом nullptr для строгой типизации. В языках с динамической типизацией (JavaScript, Python) null часто дополняется значением undefined (JavaScript) или None (Python), которые семантически близки, но имеют разные контексты использования.
Типы null в разных языках программирования
C и C++
В C и C++ null-указатель — это константа NULL (обычно (void*)0) или литерал 0. В C++11 появилось ключевое слово nullptr, которое имеет тип std::nullptr_t и неявно преобразуется в любой тип указателя. Использование NULL в C++ считается устаревшим, так как NULL может быть неявно преобразован в целочисленный тип, что приводит к неоднозначностям при перегрузке функций.
Java
В Java null — это специальное литеральное значение, которое может быть присвоено любой переменной ссылочного типа (объекту, массиву, строке). При попытке вызова метода или доступа к полю у объекта, равного null, возникает исключение NullPointerException. В Java нет примитивного типа null; null не является объектом и не имеет методов.
C#
В C# null — это значение по умолчанию для ссылочных типов. Начиная с C# 2.0, появились nullable-типы для значимых типов (например, int?), которые могут принимать null. В C# 8.0 введены nullable-ссылочные типы, позволяющие компилятору предупреждать о потенциальных разыменованиях null.
JavaScript
В JavaScript null — это примитивное значение, обозначающее «ничего», «пусто» или «неизвестное значение». Тип null в JavaScript — object (что является исторической ошибкой языка). Отдельно существует undefined, который обозначает отсутствие присвоенного значения. Различие: null обычно присваивается явно, а undefined — автоматически, когда переменная объявлена, но не инициализирована.
Python
В Python аналогом null является None — единственный объект типа NoneType. None используется для обозначения отсутствия значения. В Python нет отдельного null-указателя; None — это объект-синглтон, который можно сравнивать с помощью оператора is.
SQL
В базах данных NULL — это специальное значение (не равное ничему, даже самому себе), обозначающее отсутствие данных. В SQL NULL не участвует в обычных сравнениях: NULL = NULL возвращает не true, а UNKNOWN. Для проверки на NULL используются операторы IS NULL и IS NOT NULL. NULL в SQL может возникать при отсутствии значения в столбце, при внешних соединениях (OUTER JOIN) или при агрегации пустых наборов.
Проблемы, связанные с null
Ошибка разыменования нулевого указателя (Null Pointer Dereference)
Наиболее распространённая ошибка — попытка получить доступ к полю или вызвать метод у объекта, равного null. В языках со статической типизацией (Java, C#) это приводит к исключению времени выполнения; в C/C++ — к неопределённому поведению (часто — к аварийному завершению программы). По оценкам, ошибки, связанные с null, составляют значительную долю всех программных дефектов.
Неоднозначность семантики
Null может означать:
- Отсутствие значения (например, поле не заполнено).
- Неизвестное значение.
- Ошибку (например, функция не смогла вернуть результат).
- Пустой объект (например, пустой список как объект, а не null).
Эта неоднозначность часто приводит к путанице и необходимости дополнительных проверок.
Проблемы с производительностью
Частые проверки на null (if (x != null)) увеличивают объём кода и могут снижать производительность, особенно в критичных участках. В некоторых языках (Java, C#) компилятор генерирует проверки на null для каждого вызова виртуального метода, что также влияет на скорость.
Подходы к борьбе с null
Null-безопасные языки
Некоторые языки программирования полностью исключают null из системы типов, заменяя его опциональными типами (Option, Maybe). Примеры:
- Haskell — тип
Maybe a(Nothing или Just a). - Rust — тип
Option<T>(None или Some(T)). - Swift — опциональные типы (Optional<T>).
- Kotlin — nullable-типы (
String?) и безопасные вызовы (?.).
В этих языках компилятор заставляет программиста явно обрабатывать случай отсутствия значения, что практически исключает ошибки разыменования null.
Null-объект (Null Object Pattern)
Паттерн проектирования, при котором вместо null используется специальный объект-заглушка, реализующий тот же интерфейс, но с пустыми (безопасными) методами. Например, вместо null-ссылки на логгер используется NullLogger, который ничего не делает.
Optional и Maybe
В Java 8 появился класс Optional<T>, который явно указывает на возможность отсутствия значения. Аналогичные типы есть в C# (Nullable<T>), Swift (Optional), Kotlin и других языках. Использование Optional делает код более читаемым и снижает риск NullPointerException.
Аннотации и статический анализ
В языках со статической типизацией (Java, C#, Kotlin) используются аннотации (@Nullable, @NonNull) и инструменты статического анализа (например, IntelliJ IDEA, SpotBugs, Checker Framework), которые предупреждают о потенциальных null-ошибках на этапе компиляции.
Применение null в реальных проектах
- Базы данных: NULL используется для обозначения отсутствующих данных, что критически важно для корректной работы запросов и отчётов.
- API и веб-сервисы: В JSON null обозначается ключевым словом
nullи используется для передачи отсутствующих полей. - Графические интерфейсы: В UI-фреймворках null может означать отсутствие выбранного элемента, пустой контейнер или неинициализированный виджет.
- Обработка ошибок: В некоторых языках (например, в Go) null (nil) используется для возврата ошибки как значения (функция возвращает результат и nil-ошибку при успехе, или nil-результат и объект ошибки при неудаче).
Интересные факты
- Тони Хоар, изобретатель null, в 2009 году на конференции QCon публично извинился за это изобретение, назвав его «ошибкой на миллиард долларов».
- В языке C++
nullptrимеет типstd::nullptr_t, и его можно использовать в шаблонах и перегрузке функций, что невозможно сNULL. - В JavaScript
typeof nullвозвращает"object"— это официально признанная ошибка, которую не исправляют из соображений обратной совместимости. - В SQL
NULLне равен самому себе:NULL = NULLвозвращаетUNKNOWN, а неTRUE. Это приводит к неожиданным результатам при использованииWHERE column = NULL(нужно писатьIS NULL). - В некоторых языках (например, в Smalltalk) null отсутствует как концепция — вместо него используется специальный объект
nil, который является экземпляром классаUndefinedObjectи может безопасно обрабатывать сообщения (например,nil sizeвозвращает 0).
Критика
Концепция null подвергается критике по нескольким причинам:
- Она нарушает принцип типовой безопасности, так как любая ссылка может оказаться null.
- Она приводит к большому количеству runtime-ошибок, которые трудно отловить на этапе компиляции.
- Она усложняет понимание кода, так требует повсеместных проверок.
- Она не имеет чёткой семантики: null может означать «отсутствие», «неизвестность», «ошибку» или «пустоту».
Альтернативные подходы (опциональные типы, null-объекты, монады) считаются более безопасными и выразительными, хотя и требуют большего объёма кода в некоторых случаях.
Источники
- Тони Хоар. «Null References: The Billion Dollar Mistake» (лекция на QCon 2009).
- Брайан Керниган, Деннис Ритчи. «Язык программирования C» (2-е издание).
- Джеймс Гослинг и др. «Язык программирования Java» (4-е издание).
- ECMAScript Language Specification (стандарт JavaScript).
- SQL:1999, ISO/IEC 9075.
- Документация C++ (cppreference.com).
- Документация Kotlin (kotlinlang.org).
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →