Null что это
Перейти к содержимому

Null что это

9 вещей о NULL в Java

9 вещей о NULL в Java - 1

9 Things about Null in Java by Javin Paul, DECEMBER 10, 2014 Java и null неразрывно связаны. Едва ли существует Java-программист, не встречавшийся с «null pointer exception» и это печальный факт. Даже изобретатель концепции «null» назвал ее своей ошибкой на миллиард долларов, тогда зачем Java поддерживает ее? null был здесь долгое время, и я полагаю, создатели Java знают, что он создает больше проблем чем решает, так почему же они все еще мирятся с этим. И это удивляет меня еще больше, потому что философией Java было упростить вещи, вот почему они больше не возятся с указателями, перегрузкой операторов и множественным наследованием, но почему null? Ну, я действительно не знаю ответ на этот вопрос, но, что я точно знаю, не имеет значения сколько бы null критиковался Java-программистами и open-source сообществом, мы должны жить с ним. Вместо того чтобы сожалеть, лучше узнать больше и быть уверенным что мы используем null правильно.

Почему Вы должны узнать о null в Java?

Что есть null в Java

Перво-наперво, null это ключевое слово в Java, так же как public , static или final . Регистр учитывается, Вы не можете писать null как Null или NULL, компилятор не распознает его и будет выброшена ошибка.

Зачастую, с этим встречаются программисты, перешедшие с других языков программирования, но при использовании современных IDE проблема становится незначительной. В наши дни, IDE вроде Eclipse или NetBeans могут исправлять эту ошибку пока Вы набираете код, но в эпоху Notepad, Vim и Emacs, это была распространенная проблема, которая могла съесть кучу драгоценного времени.

Так же, как каждый примитив имеет значение по умолчанию, например, у int это 0, у boolean это false, null это значение по умолчанию любых ссылочных типов, проще говоря, для всех объектов. Так же, как при создании логической переменной ее значение по умолчанию равно false, так и любые ссылочные переменные в Java по умолчанию будут равны null. Это истинно для всех типов переменных: переменной-члена или локальной переменной, переменной экземпляра или статической переменной, кроме того, компилятор будет ругаться, если Вы используете локальную переменную не проинициализировав ее.

Это истинно как для статических, так и для не статических объектов, как Вы можете видеть здесь, я сделал myObj статической ссылкой, так что я могу использовать ее непосредственно в методе main , который является статическим методом и не позволяет обращаться к не статическим переменным изнутри.

Несмотря на распространенное заблуждение, null это не объект ( Object ) и ни тип. Это просто специальное значение, которое может быть назначено любому ссылочному типу, и Вы можете привести null к любому типу, как показано ниже:

Как Вы можете видеть, приведение null к любому ссылочному типу пройдет успешно как во время компиляции, так и во время выполнения программы. В отличии от того, что многие из Вас возможно подумали, это не приведет к выбрасыванию NullPointerException .

null может быть назначен только ссылочному типу, Вы не можете назначить null примитивной переменной вроде int , double , float или boolean . Компилятор выразит Вам свое недовольство если Вы сделаете как показано ниже:

Как Вы можете видеть, когда мы непосредственно присваиваем null примитиву, то получаем ошибку процесса компиляции, но, если присвоить null объекту класса-обертки, а затем присвоить этот объект соответствующему примитивному типу, компилятор не отреагирует, но мы будем вознаграждены null pointer exception во время выполнения. Это происходит из-за авто упаковки ( autoboxing ) в Java, и мы еще встретимся с ним в следующем пункте.

Любой класс-обертка со значением null будет выбрасывать java.lang.NullPointerException когда Java распакует( unbox ) его в примитивную переменную. Некоторые программисты делают ошибку допуская, что авто упаковка( autoboxing ) позаботится о конвертации null в значение по умолчанию для соответствующего примитивного типа, например, 0 для int , false для boolean и т.д., но это не верно, в чем можно убедиться ниже:

Но, когда Вы запустите данный фрагмент кода, в консоли Вы увидите

Это часто происходит при работе с HashMap и Integer key . Выполнение кода, показанного ниже прервется, как только Вы его запустите.

Этот код выглядит очень простым и безобидным. Вы просто подсчитываете сколько раз число встречается в массиве, классическая техника нахождения дубликатов. Разработчик берет предыдущее подсчитанное количество, увеличивает его на единицу и вставляет обратно в Map . Он мог бы подумать, что авто-упаковка позаботится о преобразовании Integer в int , как это делается в момент вызова метода put() , но он забывает, что если для числа подсчет еще не проводился, метод get() вернет из HashMap null, не ноль, потому что значение по умолчанию для Integer это null, а не 0, и авто-упаковка выбросит null pointer exception при попытке сконвертировать Integer в переменную int .

Оператор instanceof будет возвращать false если в качестве параметра указать любую ссылочную переменную со значением null или null сам по себе. Пример:

Это важное свойство оператора instanceof , которое делает его полезным для проверки приведения типов.

Вы знаете, что Вы не можете вызвать нестатический метод у ссылочной переменной со значением null, это вызовет NullPointerException , но Вы можете не знать, что Вы можете вызвать статический метода у ссылочной переменной со значением null. Т.к. статические методы используют статическое связывание, они не выбрасывают NullPointerException . Вот пример:

Вы можете послать null в качестве параметра метода, принимающего любой ссылочный тип, к примеру:

может быть вызван как

Это нормально с точки зрения компилятора, но дальнейшее поведение полностью зависит от метода. Null-безопасный метод не выбросит NullPointerException , а просто корректно завершится. Если бизнес логика позволяет, рекомендуется писать null-безопасные методы.

Вы можете сравнивать null используя операторы == (равно) и != (не равно), но не можете использовать его с другими арифметическими или логическими операторами, вроде < (меньше) или > (больше). В отличии от SQL, в Java null == null вернет true, как показано ниже:

null (справочник по C#)

Ключевое слово null является литералом, представляющим пустую ссылку, которая не ссылается на объект. null является значением по умолчанию для переменных ссылочного типа. Обычные типы значений не могут иметь значение NULL, за исключением типов значений, допускающих значение NULL.

В следующем примере показано возможное поведение ключевого слова null .

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

null — это экземпляр чего-то?

user avatar

Нет такого типа, которому бы соответствовал instanceof от null .

В рантайме результат оператора instanceof будет true , если значение RelationalExpression не null и ссылка может быть приведена к ReferenceType без получения исключения ClassCastException . Иначе результат будет false .

Это означает, что для любого типа E и R , для любого E o , где o == null , o instanceof R будет всегда false .

К какому типу принадлежит null ?

Есть также специальный тип — null, тип выражения null , у которого нет имени. И т.к. тип null не имеет имени, невозможно объявить переменную с типом null или привести переменную к типу null. null ссылка — единственное возможное значение выражение типа null . null всегда можно привести к любому ссылочному типу. В действительности, можно игнорировать тип null и притвориться, что null — это просто специальный литерал, который может быть любым ссылочным типом.

Что такое null ?

Как сказано в цитате из JLS выше, можно считать, что " null — это просто специальный литерал, который может быть любым ссылочным типом".

В Java null == null (что верно не для всех языков). Из описания java.lang.Object :

public boolean equals(Object obj)

Для любой не null переменной x , x.equals(null) должен возвращать false .

null также является значением по умолчанию для всех ссылочных типов.

  • Статические переменные класса, переменные экземпляра и массивы инициализируются значением по умолчанию при создании: * Для всех ссылочных типов (§4.3), дефолтное значение — null .

Вы можете использовать это свойства для отложенной инициализации, когда поле будет иметь начальное значение null до тех пор, пока оно фактически не будет использовано, где будет заменено "реальным" значением (вычисление которого может быть дорогостоящим).

Есть и другие применения. Если посмотреть на java.lang.System :

public static Console console()

Returns: The system console, if any, otherwise null.

Это очень распространённая практика: null используется для обозначения несуществующего объекта.

public String readLine() throws IOException

Returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached.

readLine() будет возвращать instanceof String для каждой строки, пока не получит null , обозначающий конец. Это позволяет обрабатывать каждую строку следующим образом:

Примечание: пустая строка — не проблема, т.к. "" != null .

Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.

If this map permits null values, then a return value of null does not necessarily indicate that the map contains no mapping for the key; it’s also possible that the map explicitly maps the key to null . The containsKey operation may be used to distinguish these two cases.

Здесь мы видим, что использование null может усложнить дело. Тут говорится, что, если такого ключа нет, будет возвращён null . Второе утверждение гласит, что даже если элемент по такому ключу есть, всё равно может вернуться null .

К примеру, java.util.Hashtable делает вещи проще путём запрета null в ключах и значениях; так что, если V get(Object key) вернёт null это однозначно говорит о том, что под таким ключом ничего нет.

Операции автоматического анбоксинга на null выбросят java.lang.NullPointerException :

Если резюмировать, то null используется как специальное значение для обозначения:

  • Не инициализированного состояния.
  • Терминальное условие
  • Несуществующий объект.
  • Неизвестное значение.

Как null представлен в памяти?

The Java Virtual Machine specification does not mandate a concrete value encoding null .

Небольшое дополнение

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *