Полезни NullPointerExceptions в Java 14

1. Общ преглед

В този урок ще продължим нашата поредица за Java 14, като разгледаме полезните NullPointerException s, което е нова функция, въведена с тази версия на JDK.

2. Традиционен NullPointerException s

На практика често виждаме или пишем код, който веригира методи в Java. Но когато този код изхвърли NullPointerException , може да стане трудно да се знае откъде произхожда изключението.

Да предположим, че искаме да разберем имейл адреса на служител:

String emailAddress = employee.getPersonalDetails().getEmailAddress().toLowerCase();

Ако обектът на служителя , getPersonalDetails () или getEmailAddress () е нула, JVM изхвърля NullPointerException :

Exception in thread "main" java.lang.NullPointerException at com.baeldung.java14.npe.HelpfulNullPointerException.main(HelpfulNullPointerException.java:10)

Каква е основната причина за изключението? Трудно е да се определи коя променлива е нула, без да се използва дебъгер. Освен това JVM ще отпечата само метода, името на файла и номера на реда, които са причинили изключението .

В следващия раздел ще разгледаме как Java 14 чрез JEP 358 ще реши този проблем.

3. Полезни NullPointerException s

SAP внедри полезни NullPointerException s за търговския си JVM през 2006 г. Той беше предложен като подобрение за общността OpenJDK през февруари 2019 г. и бързо след това той стана JEP. Следователно, функцията беше завършена и пусната през октомври 2019 г. за JDK 14 .

По същество JEP 358 има за цел да подобри четливостта на NullPointerException s, генерирани от JVM, като описва коя променлива е нула .

JEP 358 представя подробно съобщение NullPointerException, като описва нулевата променлива, заедно с метода, името на файла и номера на реда. Той работи, като анализира инструкциите за байт кода на програмата. Следователно той е в състояние да определи точно коя променлива или израз е нула .

Най-важното е, че подробното съобщение за изключение е изключено по подразбиране в JDK 14 . За да го активираме, трябва да използваме опцията от командния ред:

-XX:+ShowCodeDetailsInExceptionMessages

3.1. Подробно съобщение за изключение

Нека помислим за стартиране на кода отново с активиран флаг ShowCodeDetailsInExceptionMessages :

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because the return value of "com.baeldung.java14.npe.HelpfulNullPointerException$PersonalDetails.getEmailAddress()" is null at com.baeldung.java14.npe.HelpfulNullPointerException.main(HelpfulNullPointerException.java:10)

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

JVM съставя подробното съобщение за изключение от две части. Първата част представлява неуспешната операция, следствие от препратка, която е нула , докато втората част идентифицира причината за нулевата препратка :

Cannot invoke "String.toLowerCase()" because the return value of "getEmailAddress()" is null

За да изгради съобщението за изключение, JEP 358 пресъздава частта от изходния код, която е избутала нулевата препратка върху стека на операндите.

3.2. Технически аспекти

Сега, когато имаме добро разбиране за това как да идентифицираме нулеви препратки с помощта на полезни NullPointerException s, нека разгледаме някои технически аспекти от него.

Първо, подробно изчисляване на съобщението се извършва само когато JVM хвърля NullPointerException - изчислението няма да се извърши, ако изрично хвърлим изключението в нашия Java код. Причината зад това е, че в тези ситуации най-вероятно вече предаваме смислено съобщение в конструктора на изключения.

На второ място, JEP 358 изчислява съобщението мързеливо, което означава само когато отпечатваме съобщението за изключение, а не когато възникне изключение . В резултат на това не би трябвало да има въздействие върху производителността за обичайните JVM потоци, където улавяме и пренасочваме изключения, тъй като не винаги отпечатваме съобщението за изключение.

И накрая, подробното съобщение за изключение може да включва имена на локални променливи от нашия изходен код . По този начин бихме могли да разгледаме това като потенциален риск за сигурността. Това обаче се случва само когато стартираме код, компилиран с активиран флаг -g , който генерира и добавя информация за отстраняване на грешки в нашия файл на класа.

Помислете за прост пример, който сме събрали, за да включим тази допълнителна информация за отстраняване на грешки:

Employee employee = null; employee.getName();

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

Cannot invoke "com.baeldung.java14.npe.HelpfulNullPointerException$Employee.getName()" because "employee" is null

За разлика от това, без допълнителна информация за отстраняване на грешки, JVM предоставя само това, което знае за променливата в подробното съобщение:

Cannot invoke "com.baeldung.java14.npe.HelpfulNullPointerException$Employee.getName()" because "" is null

Вместо името на локалната променлива ( служител ), JVM отпечатва индекса на променливата, присвоен от компилатора .

4. Заключение

В този бърз урок научихме за полезните NullPointerException s в Java 14. Както е показано по-горе, подобрените съобщения ни помагат да отстраняваме грешки по-бързо поради подробностите за изходния код, присъстващи в съобщенията за изключения.

Както винаги, пълният изходен код на статията е достъпен в GitHub.