Чому Ви повинні дізнатися про null в Java?
Тому що, якщо Ви не звернете уваги на null, будьте впевнені, Java змусить страждати від жахливогоjava.lang.NullPointerException
і Ви вивчите цей урок, але підете важчим шляхом. Написання стійкого до "падіння" коду - це мистецтво і Ваша команда, замовники та користувачі оцінять це. На мій досвід, одна з основних причин NullPointerException
це недолік знань про null в Java. Багато хто з Вас вже знайомий з null, інші зможу дізнатися деякі старі і нові речі про ключове слово null. Давайте повторимо або дізнаємося деякі важливі речі про null в Java.
Що є null в Java
Як я казав, null дуже-дуже важлива концепція у Java. Спочатку він був винайдений для позначення відсутності чогось, наприклад, відсутність користувача, ресурсу або чого завгодно, але вже протягом року спантеличив Java-програмістів безліччюnull pointer exception
. У цьому уроці, ми дізнаємося основні факти про ключове слово null в Java, вивчимо деякі прийоми як уникнути неприємностей з null pointer exceptions
і мінімізувати перевірки на null.
-
Насамперед, null це ключове слово в Java, так само як
public
,static
абоfinal
. Регістр враховується, Ви не можете писати null як Null або NULL, компілятор не розпізнає його і буде викинута помилка.Object obj = NULL; // Not Ok Object obj1 = null //Ok
Найчастіше з цим зустрічаються програмісти, які перейшли з інших мов програмування, але при використанні сучасних IDE проблема стає незначною. У наші дні, IDE на кшталт Eclipse або NetBeans можуть виправляти цю помилку доки Ви набираєте код, але в епоху Notepad, Vim та Emacs, це була поширена проблема, яка могла з'їсти купу дорогоцінного часу.
-
Так само, як кожен примітив має значення за умовчанням, наприклад, це
int
0, у boolean це false, null це значення за умовчанням будь-яких типів посилань, простіше кажучи, для всіх об'єктів. Так само, як при створенні логічної змінної її значення за замовчуванням дорівнює false, так і будь-які змінні посилання в Java за промовчанням дорівнюватимуть null. Це істинно для всіх типів змінних: змінної-члена або локальної змінної, змінної екземпляра або статичної змінної, крім того, компілятор лаятиметься, якщо Ви використовуєте локальну змінну, не проініціалізувавши її.private static Object myObj; public static void main(String args[]){ System.out.println("What is value of myObjc : " + myObj); } What is value of myObjc : null
Це істинно як для статичних, так і для не статичних об'єктів, як Ви можете бачити тут, я зробив
myObj
статичним посиланням, так що я можу використовувати її безпосередньо в методіmain
, який є статичним методом і не дозволяє звертатися до нестатичних змінних зсередини. -
Незважаючи на поширену помилку, null це не об'єкт (
Object
) і ні тип. Це просто спеціальне значення, яке може бути призначене будь-якому типу посилань, і Ви можете привести null до будь-якого типу, як показано нижче:String str = null; // null can be assigned to String Integer itr = null; // you can assign null to Integer also Double dbl = null; // null can also be assigned to Double String myStr = (String) null; // null can be type cast to String Integer myItr = (Integer) null; // it can also be type casted to Integer Double myDbl = (Double) null; // yes it's possible, no error
Як Ви можете бачити, приведення null до будь-якого типу посилань пройде успішно як під час компіляції, так і під час виконання програми. На відміну від того, що багато хто з Вас, можливо, подумав, це не призведе до викидання
NullPointerException
. -
null може бути призначений тільки посилання типу, Ви не можете призначити null примітивної змінної на кшталт
int
,double
,float
абоboolean
. Компілятор висловить Вам своє невдоволення, якщо Ви зробите як показано нижче:int i = null; // type mismatch : cannot convert from null to int short s = null; // type mismatch : cannot convert from null to short byte b = null: // type mismatch : cannot convert from null to byte double d = null; //type mismatch : cannot convert from null to double Integer itr = null; // this is ok int j = itr; // this is also ok, but NullPointerException at runtime
Як Ви можете бачити, коли ми безпосередньо привласнюємо null примітиву, то отримуємо помилку процесу компіляції, але якщо привласнити null об'єкту класу-обгортки, а потім привласнити цей об'єкт відповідному примітивному типу, компілятор не відреагує, але ми будемо винагороджені під час виконання
null pointer exception
. Це відбувається через авто упаковки (autoboxing
) в Java, і ми ще зустрінемося з ним у наступному пункті. -
Будь-який клас-обгортка зі значенням null буде викидати
java.lang.NullPointerException
коли Java розпакує(unbox
) його в примітивну змінну. Деякі програмісти роблять помилку припускаючи, що авто упаковка(autoboxing
) подбає про конвертацію null у значення за промовчанням для відповідного примітивного типу, наприклад, 0 дляint
, false дляboolean
і т.д., але це не вірно, в чому можна переконатися нижче:Integer iAmNull = null; int i = iAmNull; // Remember - No Compilation Error
Але коли Ви запустите цей фрагмент коду, в консолі Ви побачите
Exception in thread "main" java.lang.NullPointerException
Це часто відбувається при роботі з
HashMap
іInteger key
. Виконання коду, показаного нижче, перерветься, як тільки Ви його запустите.import java.util.HashMap; import java.util.Map; /** * An example of Autoboxing and NullPointerExcpetion * * @author WINDOWS 8 */ public class Test { public static void main(String args[]) throws InterruptedException { Map numberAndCount = new HashMap<>(); int[] numbers = {3, 5, 7,9, 11, 13, 17, 19, 2, 3, 5, 33, 12, 5}; for(int i : numbers){ int count = numberAndCount.get(i); numberAndCount.put(i, count++); // NullPointerException here } } }
Output: Exception in thread "main" java.lang.NullPointerException at Test.main(Test.java:25)
Цей код виглядає дуже простим та нешкідливим. Ви просто підраховуєте скільки разів кількість зустрічається в масиві, класична техніка знаходження дублікатів. Розробник бере попередню підраховану кількість, збільшує його на одиницю і вставляє назад у
Map
. Він міг би подумати, що авто-упаковка потурбується про перетворенняInteger
вint
, як це робиться в момент виклику методуput()
, але він забуває, що якщо для числа підрахунок ще не проводився, методget()
поверне зHashMap
null, не нуль, тому що значення за замовчуванням для Integer це null, а не 0, і авто-упаковка викинеnull pointer exception
при спробі конвертувати Integer у зміннуint
. -
Оператор
instanceof
повертатиме false якщо в якості параметра вказати будь-яку посилальну змінну зі значенням null або null сам по собі. Приклад:Integer iAmNull = null; if(iAmNull instanceof Integer){ System.out.println("iAmNull is instance of Integer"); }else{ System.out.println("iAmNull is NOT an instance of Integer"); }
Output : iAmNull is NOT an instance of Integer
Це важлива властивість оператора
instanceof
, яка робить його корисним для перевірки типів. -
Ви знаєте, що Ви не можете викликати нестатичний метод у змінної посилання зі значенням null, це викличе
NullPointerException
, але Ви можете не знати, що Ви можете викликати статичний метод у посилальної змінної зі значенням null. Т.к. статичні методи використовують статичне зв'язування, де вони викидаютьNullPointerException
. Ось приклад:public class Testing { public static void main(String args[]){ Testing myObject = null; myObject.iAmStaticMethod(); myObject.iAmNonStaticMethod(); } private static void iAmStaticMethod(){ System.out.println("I am static method, can be called by null reference"); } private void iAmNonStaticMethod(){ System.out.println("I am NON static method, don't date to call me by null"); } }
Output: I am static method, can be called by null reference Exception in thread "main" java.lang.NullPointerException at Testing.main(Testing.java:11)
-
Ви можете послати null як параметр методу, який приймає будь-який тип посилання, наприклад:
public void print(Object obj)
може бути викликаний як
print(null)
Це нормально з погляду компілятора, але подальша поведінка залежить від методу. Null-безпечний метод не викине
NullPointerException
, а просто коректно завершиться. Якщо бізнес-логіка дозволяє, рекомендується писати null-безпечні методи. -
Ви можете порівнювати null за допомогою операторів
==
(рівно) і!=
(не рівно), але не можете використовувати його з іншими арифметичними або логічними операторами, на кшталт<
(менше) або>
(більше). На відміну від SQL, Javanull == null
поверне true, як показано нижче:public class Test { public static void main(String args[]) throws InterruptedException { String abc = null; String cde = null; if(abc == cde){ System.out.println("null == null is true in Java"); } if(null != null){ System.out.println("null != null is false in Java"); } // classical null check if(abc == null){ // do something } // not ok, compile time error if(abc > null){ } } }
Output: null == null is true in Java
NullPointerException
, Ви зможете зробити Ваш код безпечним. Т.к. Значення null може розглядатися як порожнє або неініціалізоване значення, це часто є джерелом плутанини, ось чому так важливо документувати поведінку методу при вхідному значенні null. Завжди пам'ятайте, null це значення за замовчуванням змінних посилань, і Ви не можете викликати методи екземпляра або отримувати доступ до змінних екземпляра використовуючи null-посилання в Java.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ