Utili NullPointerExceptions in Java 14

1. Panoramica

In questo tutorial, continueremo la nostra serie su Java 14 dando un'occhiata a Helpful NullPointerException s, che è una nuova funzionalità introdotta con questa versione di JDK.

2. tradizionale NullPointerException s

In pratica, spesso vediamo o scriviamo codice che concatena metodi in Java. Ma quando questo codice genera un'eccezione NullPointerException , può diventare difficile sapere da dove ha origine l'eccezione.

Supponiamo di voler scoprire l'indirizzo email di un dipendente:

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

Se l' oggetto dipendente , getPersonalDetails () o getEmailAddress () è nullo, la JVM genera un'eccezione NullPointerException :

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

Qual è la causa principale dell'eccezione? È difficile determinare quale variabile è nulla senza utilizzare un debugger. Inoltre, la JVM stamperà solo il metodo, il nome del file e il numero di riga che ha causato l'eccezione .

Nella sezione successiva, daremo un'occhiata a come Java 14, tramite JEP 358, risolverà questo problema.

3. utili NullPointerException s

SAP ha implementato le NullPointerException utili per la propria JVM commerciale nel 2006. È stato proposto come miglioramento alla comunità OpenJDK nel febbraio 2019 e, subito dopo, è diventato un JEP. Di conseguenza, la funzione è stata completata e pubblicata nell'ottobre 2019 per la versione JDK 14 .

In sostanza, JEP 358 mira a migliorare la leggibilità delle NullPointerException , generate da JVM, descrivendo quale variabile è nulla .

JEP 358 porta un messaggio NullPointerException dettagliato descrivendo la variabile null , insieme al metodo, al nome del file e al numero di riga. Funziona analizzando le istruzioni del bytecode del programma. Pertanto, è in grado di determinare con precisione quale variabile o espressione era nulla .

Ancora più importante, il messaggio di eccezione dettagliato è disattivato per impostazione predefinita in JDK 14 . Per abilitarlo, dobbiamo utilizzare l'opzione della riga di comando:

-XX:+ShowCodeDetailsInExceptionMessages

3.1. Messaggio di eccezione dettagliato

Consideriamo di eseguire nuovamente il codice con il flag ShowCodeDetailsInExceptionMessages attivato:

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)

Questa volta, dalle informazioni aggiuntive, sappiamo che l'indirizzo email mancante dei dati personali del dipendente causa la nostra eccezione. La conoscenza acquisita da questo miglioramento può farci risparmiare tempo durante il debug.

JVM compone il messaggio di eccezione dettagliato da due parti. La prima parte rappresenta l'operazione fallita, conseguenza del fatto che un riferimento è nullo , mentre la seconda parte identifica il motivo del riferimento nullo :

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

Per creare il messaggio di eccezione, JEP 358 ricrea la parte del codice sorgente che ha inserito il riferimento null nello stack di operandi.

3.2. Aspetti tecnici

Ora che abbiamo una buona comprensione di come identificare i riferimenti nulli utilizzando le utili NullPointerException , diamo un'occhiata ad alcuni aspetti tecnici di esso.

In primo luogo, un calcolo dettagliato del messaggio viene eseguito solo quando la stessa JVM genera un'eccezione NullPointerException : il calcolo non verrà eseguito se generiamo esplicitamente l'eccezione nel nostro codice Java. La ragione di ciò è che, in queste situazioni, molto probabilmente abbiamo già passato un messaggio significativo nel costruttore di eccezioni.

In secondo luogo, JEP 358 calcola il messaggio pigramente, ovvero solo quando stampiamo il messaggio di eccezione e non quando si verifica l'eccezione . Di conseguenza, non dovrebbe esserci alcun impatto sulle prestazioni per i normali flussi JVM, in cui rileviamo e rilanciamo le eccezioni, poiché non stampiamo sempre il messaggio di eccezione.

Infine, il messaggio di eccezione dettagliato può includere nomi di variabili locali dal nostro codice sorgente . Pertanto, potremmo considerarlo un potenziale rischio per la sicurezza. Tuttavia, questo accade solo quando eseguiamo codice compilato con il flag -g attivato, che genera e aggiunge informazioni di debug nel nostro file di classe.

Considera un semplice esempio che abbiamo compilato per includere queste informazioni di debug aggiuntive:

Employee employee = null; employee.getName();

Quando eseguiamo questo codice, il messaggio di eccezione stampa il nome della variabile locale:

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

Al contrario, senza ulteriori informazioni di debug, la JVM fornisce solo ciò che sa sulla variabile nel messaggio dettagliato:

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

Invece del nome della variabile locale ( dipendente ), la JVM stampa l'indice della variabile assegnato dal compilatore .

4. Conclusione

In questo breve tutorial, abbiamo imparato a conoscere le utili NullPointerException in Java 14. Come mostrato sopra, i messaggi migliorati ci aiutano a eseguire il debug del codice più velocemente grazie ai dettagli del codice sorgente presenti nei messaggi di eccezione.

Come sempre, il codice sorgente completo dell'articolo è disponibile su GitHub.