Nullable java что это

от admin

@Nullable and @NotNull

@Nullable and @NotNull annotations let you check nullability of a variable, parameter, or return value. They help you control contracts throughout method hierarchies, and if IntelliJ IDEA spots that the contract is being violated, it will report the detected problem, and will point to the code where NullPointerException may occur.

For example, if you create a method where a parameter has the @NotNull annotation, and then call this method with a parameter that potentially can be null, IntelliJ IDEA will highlight the problem on the fly.

The check is done by the Constant conditions & exceptions and @NotNull/@Nullable problems inspections. You can configure the way these inspections work in the Settings Ctrl+Alt+S dialog. Go to Editor | Inspections | Java | Probable bugs .

When you compile your project, the IDE adds assertions to all methods and parameters annotated with the @NotNull annotation. The assertions will fail if null is passed in code where @NotNull is expected. You can disable this option and configure the list of annotations in the Settings dialog Ctrl+Alt+S . Go to Build, Execution, Deployment | Compiler .

@Nullable

The @Nullable annotation helps you detect:

Method calls that can return null

Variables (fields, local variables, and parameters), that can be null

Methods with the @Nullable annotation in the parent method can have either @Nullable or @NotNull annotations in the child class method.

The @Nullable annotation of the parameter in the parent method requires the @Nullable annotation in the child class method parameter.

@NotNull

The @NotNull annotation is, actually, an explicit contract declaring that:

A method should not return null

Variables (fields, local variables, and parameters) cannot hold a null value

IntelliJ IDEA warns you if these contracts are violated.

The @NotNull annotation of the parent method requires the @NotNull annotation for the child class method.

Methods with the @NotNull annotation of the parameter in the parent method can have either @Nullable or @NotNull annotations (or none of them) in the child class method parameter.

If @NotNull has the _TYPE_USE_ target, it’s applied to the array element type, not to the array type itself. To annotate the array type with the TYPE_USE annotation, use the byte @NotNull [] bytes syntax.

@Nullable annotation usage

What’s the meaning of @Nullable here? Does it mean the input could be null ?

Without the annotation, the input can still be null, so I guess that’s not just it?

4 Answers 4

It makes it clear that the method accepts null values, and that if you override the method, you should also accept null values.

It also serves as a hint for code analyzers like FindBugs. For example, if such a method dereferences its argument without checking for null first, FindBugs will emit a warning.

kevinarpe's user avatar

This annotation is commonly used to eliminate NullPointerExceptions . @Nullable says that this parameter might be null . A good example of such behaviour can be found in Google Guice. In this lightweight dependency injection framework you can tell that this dependency might be null . If you would try to pass null without an annotation the framework would refuse to do it’s job.

What is more, @Nullable might be used with @NotNull annotation. Here you can find some tips on how to use them properly. Code inspection in IntelliJ checks the annotations and helps to debug the code.

Adam Sznajder's user avatar

Different tools may interpret the meaning of @Nullable differently. For example, the Checker Framework and FindBugs handle @Nullable differently.

Granted, there are definitely different thinking, in my world, I cannot enforce «Never pass a null» because I am dealing with uncontrollable third parties like API callers, database records, former programmers etc. so I am paranoid and defensive in approaches. Since you are on Java8 or later there is a bit cleaner approach than an if block.

You can also throw some exception in there by swapping .orElse to orElseThrow(() -> new Exception(«Dont’ send a null»)) .

If you don’t want to use @Nullable, which adds nothing functionally, why not just name the parameter with mayBe. so your intention is clear.

9 вещей о NULL в Java

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

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, как показано ниже:

Name already in use

JBook / start / null_war.md

  • Go to file T
  • Go to line L
  • Copy path
  • Copy permalink
  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

Здесь будет описано и рассказано про null с точки зрения разработчика на Java .

Для начала надо понять, как к null пришло человечество.

Во время написания кода в объектно-ориентированной парадигме вы представляете свою программу в виде совокупности и взаимодействия объектов, каждый из которых является экземпляром определённого класса.

И всё бы ничего, но что делать, если вам необходимо обозначить отсутствие объекта? Например, отсутствие пользователя, какого-то ресурса и т.д.

Представьте, что вы написали класс, описывающий пользователя, одним из полей класса является адрес электронной почты — email . Но не у всех пользователей есть email : кто-то вообще его не использует, кто-то не хочет указывать его или собирается это сделать позже.

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

Вам необходимо обозначить отсутствие объекта, и вот тут-то на сцену и выходит null .

Казалось бы, всё и на этом тему можно закрывать, ведь все довольны и счастливы! Не совсем.

Если вы попытаетесь вызвать любой метод на null , то неизбежно получите java.lang.NullPointerException . А если исключение не будет обработано, то это неизбежно послужит тому, что ваше приложение аварийно завершится.

В этом и состоит основная проблема использования null : это потенциальный источник java.lang.NullPointerException .

Что такое null в Java ?

«There is also a special null type, the type of the expression null, which has no name. Because the null type has no name, it is impossible to declare a variable of the null type or to cast to the null type. The null reference is the only possible value of an expression of null type. The null reference can always be cast to any reference type. In practice, the programmer can ignore the null type and just pretend that null is merely a special literal that can be of any reference type.» JLS 4.1

Из чего следует, что null в Java — это особое значение, оно не ассоциируется ни с каким типом (оператор instanceOf возвращает false , если в качестве параметра указать любую ссылочную переменную со значением null или null сам по себе) и может быть присвоено любой ссылочной переменной, а также возвращено из метода.

  1. Каждое возвращаемое значение ссылочного типа может быть null .
  2. Каждое значение параметра ссылочного типа может также быть null .

Чувствуете масштаб проблемы? Добавьте сюда ещё и тот факт, что null является значением по умолчанию для ссылочных типов, чтобы получить полное представление о ситуации с null -ами!

NPE

Однако, будет неверным считать, что null — это всегда зло, что он неуместен только из-за того, что его неаккуратное использование может привести к ошибкам. И ножом можно нанести повреждения, но это не делает нож плохим инструментом.

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

Но, как и в ситуации с ножом, у null тоже есть правила безопасности и о них мы и поговорим.

Рассмотрим следущий код:

Подобный способ довольно распространен, вы пишите метод, а когда нет возвращаемого значения — отдаете null . А теперь представьте как вы будете пользоваться (и как обрекаете на это других) этим методом?

Вы уже не можете просто взять и сделать:

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

Но надо понимать, что нет ничего плохого в null как в значении, но null как reference — однозначное и чистое зло.

Это значит, что поле класса вполне может быть хранить внутри null , проблемы начинаются в момент, когда начинается работа с этим полем — использование его как ссылку.

Для примера рассмотрим старого доброго Person -а, который скоро уже в суд подаст на нас за преследования:

Как уже было сказано не раз, null — это значение по умолчанию для ссылочных типов. Соответственно, по умолчанию у объектов Person в поле email будет null .

В целом, подобный код часто встречается и это не плохо: у нас есть обязательные значения( name и age ) и необязательные, которые могут отсутствовать — электронный адрес.

Не доверяй и проверяй

Самая явная и очевидная проверка на null в Java выглядит следующим образом:

В Java 7+ появился вспомогательный класс java.util.Objects , который содержит вспомогательные методы проверки на null :

Однако, эти методы были добавлены в основном для Java Stream API , для удобного использования в filter . Да и на мой взгляд, обычная проверка более читабельна и явная, сравните:

Несмотря на все наши усилия и договорённости, null может также просочиться в объект ещё на этапе его создания.

Объект будет создан, несмотря на то, что не ожидается, что поле userName может быть null . Логичным решением будет потребовать уже на этапе создания объекта невозможность присвоения null значения такому полю.

Т.е. перед инициализацией проверить допустимость значений, которые получены конструктором.

К счастью, для этого в уже знакомом java.util.Objects есть необходимые методы:

Благодаря чему, наш Person приобретает дополнительные проверки и вы всегда быстро поймёте какое поле было проинициализировано неправильно:

Вопрос:

Постойте, ведь в Java давно есть assert , а что насчёт них?

Ответ:

Да, есть и их также можно использовать для валидации значений:

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

  1. По умолчанию они отключены.
  2. Такая проверка, в случае проблемы, кидает java.lang.AssertionError , что осложняет обработку исключений в проекте и дальнейшую отладку.

Более подробно о проверках.

Аккуратность в проверках

Помните, что вызов метода на null неизбежно породит java.lang.NullPointerException :

Поэтому, при работе с константами, enum -ами и т.д. вызывайте методы на константах, как наиболее безопасном месте.

Примитивы не так уж и примитивны

Будьте аккуратны с boxing/unboxing .

Как вы думаете, что будет при выполнении следующего кода:

А будет уже знакомый и горячо любимый java.lang.NullPointerException , возникший как раз в unboxing -е.

Поэтому будьте аккуратнее с boxing/unboxing и null -ами, по возможности пользуйтесь примитивами.

Аккуратнее со строками

Помните, что при конкатенации строк, если там затесалось null значение, не будет java.lang.NullPointerException , но и игнорирования null не будет:

В итоге в обоих случаях будет: hello null !

Человечество, кому повезло не быть разработчиками, ещё не готово к таким наскальным надписям, поэтому, дабы не удивляться null -ам в UI и логах, используйте java.util.Objects , Google Guava или Apache Commons библиотеки.

Например, как это сделано в java.util.Objects :

Но я рекомендую использовать Apache Commons и класс StringUtils. Удобная и безопасная работа со строками с учётом null -ов.

В случае написания функциональности, где не все параметры всегда предоставляются, обычно велик соблазн написать один метод и далее использовать его, передавая при необходимости null в параметры, которые могут отсутствовать.

Например, обновление статуса с дополнительной информацией (по возможности):

При этом, details вполне может отсутствовать и зачастую использование сводится к:

В таком случае, лучше перегрузить метод и сделать:

Старайтесь минимизировать явную передачу null в методы.

Во-первых, null в методе делает его менее читабельным, особенно, если null значений несколько, например:

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

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

Отсутствие значения не всегда null

Одной из самых популярных ошибок в использовании null является возвращение его там, где ожидается коллекция данных.

Разберём пример: вы написали телефонную книгу, где есть возможность получить список номеров по имени абонента:

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

Казалось бы, всё правильно, но нет!

Там, где контракт метода говорит о том, что будет возвращена коллекция данных по какому-то фильтру (в нашем случае — имени)всегда возвращайте пустую коллекцию, при отсутствии данных.

Точно также, если вы разрабатываете функционал, где одним из параметров является необязательная коллекция данных: не делайте возможность передачи вместо неё null :

Если tags необязательное значение для поиска, то при отсутствии значения передавайте пустое множество:

Либо сделайте два метода: с tags в сигнатуре и без.

Точно тот же совет, когда коллекция — это поле класса.

Например, вам необходимо множество кодов ошибок в валидаторе значений:

Если нет множества(не инициализировали, отсутствует) — сделайте его пустым множеством. Но не делайте его null !

Как вариант можно возвращать ещё итератор.

Отстутствие значения при работе с коллекциями — это пустая коллекция. При работе с коллекциями и отношением данных one-to-many отсутствие значения — это и есть пустая коллекция.

Начиная с Java 8+ для борьбы с null был добавлен класс java.util.Optional . Класс был добавлен для того, чтобы дать возможность разработчикам явно показывать, что значения может не быть.

Если объяснять на пальцах, то java.util.Optional — это просто контейнер, в который вы оборачиваете значение. При отсутствии значения у вас пустой контейнер, при существовании значения — у вас контейнер со значением.

Для работы Optional с примитивами существует: java.util.OptionalInt , java.util.OptionalLong и java.util.OptionalDouble .

Для примера, пусть необходим метод, который в телефонной книге ищет пользователя по имени и фамилии (как уникальным идентификаторам пользователя в нашей реализации):

Очевидно, что может возникнуть ситуация, когда будет произведен поиск несуществующего пользователя (например, не зарегестрированного у нас).

Что делать в таком случае?

Варианта, на самом деле, три:

  1. Кинуть исключение
  2. Вернуть null
  3. Вернуть Optional

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

В таком случае, использование может быть в виде:

Помимо примитивной проверки в if -е Optional можно(и нужно) использовать в Java Stream API :

Однако, Optional , на мой взгляд, имеет смысл использовать только в качестве возвращаемых значений. Определенно не стоит его использовать в качестве параметров метода, поскольку при использовании Optional в качестве параметров метода теряется читабельность, код становится более громоздким, проверят на null придеться всё равно и поэтому лучше предоставить действительное значение или сделать перегрузку метода в случаях, когда параметр необязателен.

Также и с полями класса. Нет смысла делать поля класса Optional , так как это будет не Java Bean , также Optional является не сериализуемым классом и т.д.

Есть три способа создать Optional :

  1. Optional.empty() в случае, если вы уверены, что необходимо вернуть пустой контейнер.
  2. Optional.of(value) в случае, если вы уверены, что значение, value , которое вы собираетесь положить в контейнер совершенно точно не null .
  3. В противном случае используйте Optional.ofNullable(value) .

Никогда не смешивайте null и Optional :

Это путь в ад и к ненависти.

Доверяйте, но с аннотациями

Но как быть тому, кто будет использовать ваш код, понять, какие поля вы какие поля могут по нашей задумке быть null , а какие — нет, и это явная ошибка?

Ведь это нам, как разработчикам этого кода, прозрачно и понятно, что email -а может не быть и это нормальное поведение кода. Другим разработчикам, да и нам самим через неделю, это абсолютно не ясно — и из этого возникает мысль, что было бы удобно как-то разметить наш класс, показать, где ожидаем null и это заложено, а где не ожидаем и это ошибка на миллион долларов.

Может ли поле быть с null или нет — это уже метаинформация о поле. А, значит, логично воспользоваться аннотациями.

К сожалению, в Java нет какого-то общего стандарта, и существует несколько видов аннотаций для этого, например:

В целом, я уверен, существуют еще несколько, но я выделил наиболее популярные (исключая Android специфичные) на данный момент.

Какую выбрать и как использовать?

На самом деле, вопрос сложный, но я в своих проектах пользуюсь тем, что предоставляет JSR-305, т.е javax.annotation.Nonnull и т.д.

Почему? Дело в том, что я стараюсь избегать ссылок на IDE специфичные аннотации, поэтому jetbrains , lombok и eclipse отпадают. Остается только javax.annotation и javax.validation.constraints . Я сделал выбор в пользу первой как более простой, наглядной и распространённой. Вообще, это довольно холиварный вопрос, но, если вы пишите на Java 8 , то JSR-305 будет к месту.

Благодаря плагину и аннотациям из JSR-305 получается разметить и сгенерировать код с билдерами и проверками на null :

Аннотация @ParametersAreNonnullByDefault на классе говорит о том, что все параметры в методах по умолчанию @Nonnull .

Но не возвращаемые значения! Возвращаемые значения надо размечать вручную самому и явно.

Это довольно удобно и практично.

Однако, надо понимать, что эти аннотации — не более, чем разметка, чтобы облегчить и структурировать себе и потомкам понимание логики.

Грубо говоря, это как разметка на дороге, вы понимаете, где может быть опасное место, а где в целом безопасный отрезок трассы, но это не защитит вас от грузовика по встречной полосе, если кто-то на нём вырулит:

Аннотации — не более, чем рекомендации и описание правил, которые в идеале должны соблюдать все участники проекта. Но они могут и не соблюдать их!

При разработке не бойтесь null , но старайтесь минимизировать его использование. Нет ничего плохого в null как в значении, но null как reference — однозначное и чистое зло.

По возможности, избегайте использование null в качестве возвращаемых значений, предпочитая Optional или исключение. Не задействуйте null для указания ошибок: лучше выбрасывайте явное исключение.

Помните, что отсутствие значения у коллекции — это чаще всего пустая коллекция или пустой итератор.

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

Старайтесь использовать pre-conditions с помощью Objects.requireNonNull — чем раньше вы поймёте где проблема и с чем, тем лучше.

Будьте аккуратнее со строками и boxing/unboxing !

Отдельную благодарность за ревью и помощь автор хочет выразить следующим людям из твиттера:

Читать:
Расширить значение ttl asus что это

Похожие статьи