Открыть сервисСервис

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).
Заметили ошибку или не согласны с информацией в статье? Напишите нам support@bfometr.ru