Статьи

Лучшие сообщения NPE в JDK 14

Мое сообщение в блоге за март 2019 года « Лучшее сообщение по умолчанию NullPointerException Сообщения приходят на Java? ”Было написано, когда проект JEP для улучшенных сообщений NullPointerException еще не был нацелен на конкретный выпуск JDK. С тех пор этот проект JEP стал JEP 358 («Полезные исключения NullPointerException») , который был предназначен для JDK 14 . Более того, начальная реализация ( JDK-8218628 ) уже находится в ветви JDK 14 и доступна для использования в сборке 20 раннего доступа JDK 14 (2019/10/23) .

В этом посте я продемонстрирую пример кода, представленный в моем предыдущем посте, для JDK 14 Early Access Build 20, чтобы продемонстрировать предоставленные дополнительные подробности. Чтобы увидеть этот пример кода, который был написан для преднамеренного введения множества ситуаций, приводящих к NullPointerException , см. Предыдущую публикацию или просмотр исходного кода на GitHub .

После загрузки JDK 14 Early Access Build 20 и указания моего пути я вижу следующее при запуске java -version :

1
2
3
openjdk version "14-ea" 2020-03-17
OpenJDK Runtime Environment (build 14-ea+20-879)
OpenJDK 64-Bit Server VM (build 14-ea+20-879, mixed mode, sharing)

С JDK 14 Early Access Build 20, настроенным соответствующим образом, я перестроил исходный код, упомянутый ранее, а затем повторно запустил код с помощью средства запуска java без каких-либо новых опций. Вывод этого (показанный ниже) существенно не отличается от вывода с предыдущими версиями JDK.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
=========================================
| #1: Element [0] on null boolean array |
=========================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateFirstExampleIndexAccessOnNullBooleanArray(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=================================
| #2: .length on null boolean[] |
=================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateSecondExampleLengthOnNullBooleanArray(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=======================================
| #3: Assigning float to null float[] |
=======================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateThirdExampleAssigningValueToElementOfNullFloatArray(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
======================================
| #4: Accessing field on null object |
======================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateFourthExampleAccessInstanceFieldOfNullObject(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
===================
| #5: throw null; |
===================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateFifthExampleThrowingConstantNull(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
================================================
| #6: Method invocation on null instance field |
================================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateSixthExampleMethodInvocationOnNullInstanceField(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=============================================
| #7: synchronized() on null instance field |
=============================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateSeventhExampleSynchronizedNullInstanceField(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
==========================================================================
| >>> Null Lost in Long Series of Method Invocations in Single Statement |
==========================================================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateNullLostInSeriesOfMethodInvocationsInSingleStatement(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=======================================================
| >>> Null Lost in Dereferenced Constructor Arguments |
=======================================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateNullLostInConstructorAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
==================================================
| >>> Null Lost in Dereferenced Method Arguments |
==================================================
 
java.lang.NullPointerException
 at dustin.examples.npe.NpeDemo.demonstrateNullLostInMethodAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)

Как показывает вышеприведенный вывод, даже с новым JDK 14 Early Access Build 20 я не вижу никакой новой подробной информации о NullPointerException когда я запускаю свое приложение в обычном режиме. Я включил этот вывод, чтобы показать, что требуется специальный флаг, чтобы включить более подробные NullPointerException и чтобы было удобнее сравнивать вывод без дополнительных подробностей и с ними. В следующем выводном листинге показаны дополнительные сведения, предоставляемые при -XX:+ShowCodeDetailsInExceptionMessages запуска Java флаг -XX:+ShowCodeDetailsInExceptionMessages :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
=========================================
| #1: Element [0] on null boolean array |
=========================================
 
java.lang.NullPointerException: Cannot load from byte/boolean array because "<local1>" is null
 at dustin.examples.npe.NpeDemo.demonstrateFirstExampleIndexAccessOnNullBooleanArray(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=================================
| #2: .length on null boolean[] |
=================================
 
java.lang.NullPointerException: Cannot read the array length because "<local1>" is null
 at dustin.examples.npe.NpeDemo.demonstrateSecondExampleLengthOnNullBooleanArray(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=======================================
| #3: Assigning float to null float[] |
=======================================
 
java.lang.NullPointerException: Cannot store to float array because "<local1>" is null
 at dustin.examples.npe.NpeDemo.demonstrateThirdExampleAssigningValueToElementOfNullFloatArray(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
======================================
| #4: Accessing field on null object |
======================================
 
java.lang.NullPointerException: Cannot read field "nullInstanceField" because "<local1>" is null
 at dustin.examples.npe.NpeDemo.demonstrateFourthExampleAccessInstanceFieldOfNullObject(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
===================
| #5: throw null; |
===================
 
java.lang.NullPointerException: Cannot throw exception because "null" is null
 at dustin.examples.npe.NpeDemo.demonstrateFifthExampleThrowingConstantNull(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
================================================
| #6: Method invocation on null instance field |
================================================
 
java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "this.nullInstanceField" is null
 at dustin.examples.npe.NpeDemo.demonstrateSixthExampleMethodInvocationOnNullInstanceField(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=============================================
| #7: synchronized() on null instance field |
=============================================
 
java.lang.NullPointerException: Cannot enter synchronized block because "this.nullInstanceField" is null
 at dustin.examples.npe.NpeDemo.demonstrateSeventhExampleSynchronizedNullInstanceField(Unknown Source)
 at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
==========================================================================
| >>> Null Lost in Long Series of Method Invocations in Single Statement |
==========================================================================
 
java.lang.NullPointerException: Cannot invoke "dustin.examples.npe.DysfunctionalLocation$Province.getCity()" because the return value of "dustin.examples.npe.DysfunctionalLocation$Nation.getProvince()" is null
 at dustin.examples.npe.NpeDemo.demonstrateNullLostInSeriesOfMethodInvocationsInSingleStatement(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
=======================================================
| >>> Null Lost in Dereferenced Constructor Arguments |
=======================================================
 
java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because "<local6>" is null
 at dustin.examples.npe.NpeDemo.demonstrateNullLostInConstructorAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)
 
==================================================
| >>> Null Lost in Dereferenced Method Arguments |
==================================================
 
java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because "<local6>" is null
 at dustin.examples.npe.NpeDemo.demonstrateNullLostInMethodAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source)
 at dustin.examples.npe.NpeDemo.main(Unknown Source)

В JEP 358 объясняется использование этого флага для просмотра дополнительных сведений об NullPointerException : «Эта функция может быть переключена с помощью новой boolean опции командной строки -XX { + | - } ShowCodeDetailsInExceptionMessages -XX { + | - } ShowCodeDetailsInExceptionMessages . Опция сначала будет иметь значение «по умолчанию», чтобы сообщение не печаталось. Он предназначен для включения деталей кода в сообщениях об исключениях по умолчанию в более поздней версии » Как мы видим, эта функция изначально отключена по умолчанию, но в будущем планируется включить более подробные сообщения NullPointerException .

Недавний твит задал вопрос: «Как это будет работать, если байт-код не содержит имен переменных?» Вопрос продолжился, приведя конкретный пример: «Предположим, у нас есть код, подобный Object a = ....; a.getName(); //NPE Object a = ....; a.getName(); //NPE Object a = ....; a.getName(); //NPE Какие сообщения NPE будут иметь? » Хотя пример этого включен в мою серию тестов, показанных ранее, я подумал, что приведу здесь более конкретный пример в ответ на этот вопрос. Следующий листинг кода (который также доступен на GitHub ) показывает код, адаптированный из примера, используемого в твите.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package dustin.examples.npe;
 
/**
 * Simple demonstration to answer Tweet-ed question
 * "How it will work if bytecode doesn't contain variable names?"
 */
public class TwoDoubleWhiskeyTweetExample
{
   public static void main(final String[] arguments)
   {
      final Person person = null;
      person.getName(); //NPE
   }
    
   public static class Person
   {
      private String name;
 
      public Person(final String newName)
      {
         name = newName;
      }
 
      public String getName()
      {
         return name;
      }
   }
}

На следующем снимке экрана показан результат запуска этого простого приложения с JDK 14 Early Access Build 20 без, а затем с флагом запуска java -XX:+ShowCodeDetailsInExceptionMessages .

Как показывает снимок экрана, использование флага -XX:+ShowCodeDetailsInExceptionMessages с JDK 14 раннего доступа Build 20 предоставляет дополнительную информацию, относящуюся к этому простому примеру NullPointerException : «Невозможно вызвать» dustin.examples.npe.TwoDoubleWhiskeyTweetExample $ Person.getName () «Потому что« <local1> »имеет значение null»

Пример, который проще и даже ближе к исходному примеру, представленному в вопросе Tweet-ed, доступен на GitHub .

JEP 358Полезные исключения NullPointerException ») может быть не таким кричащим, как некоторые другие JEP, которые приходят в новые выпуски JDK, но в конечном итоге это может быть тот, который в конечном итоге обеспечивает большую ценность для разработчиков Java на ежедневной основе, чем некоторые из его более ярких коллег. Есть множество примеров, где это будет полезно, и многие из этих примеров ситуаций описаны в самом JEP и в моих примерах кода, на которые есть ссылки в этом посте.

Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG . См. Оригинальную статью здесь: Лучшие Сообщения NPE в JDK 14

Мнения, высказанные участниками Java Code Geeks, являются их собственными.