Che cos'è una NullPointerException e come si risolve?


209

Cosa sono le eccezioni puntatore nullo ( java.lang.NullPointerException) e cosa le causa?

Quali metodi / strumenti possono essere utilizzati per determinare la causa in modo da impedire all'eccezione di causare la chiusura anticipata del programma?

Risposte:


3833

Quando dichiari una variabile di riferimento (cioè un oggetto) stai realmente creando un puntatore a un oggetto. Considera il codice seguente in cui dichiari una variabile di tipo primitivo int:

int x;
x = 10;

In questo esempio, la variabile xè an inte Java la inizializzerà 0per te. Quando si assegna il valore di 10sulla seconda riga, il valore di 10viene scritto nella posizione di memoria a cui fa riferimento x.

Ma, quando provi a dichiarare un tipo di riferimento , accade qualcosa di diverso. Prendi il codice seguente:

Integer num;
num = new Integer(10);

La prima riga dichiara una variabile denominata num, ma in realtà non contiene ancora un valore primitivo. Invece, contiene un puntatore (perché il tipo è Integerche è un tipo di riferimento). Dal momento che non hai ancora detto a cosa puntare, Java lo imposta null, il che significa " Non sto indicando nulla ".

Nella seconda riga, la newparola chiave viene utilizzata per istanziare (o creare) un oggetto di tipo Integere la variabile del puntatore numviene assegnata a Integerquell'oggetto.

La NullPointerExceptionverifica quando si dichiara una variabile, ma non ha creato un oggetto e assegnare alla variabile prima di tentare di utilizzare i contenuti della variabile (denominata dereferenziazione ). Quindi stai indicando qualcosa che in realtà non esiste.

La dereferenziazione di solito si verifica quando si utilizza .per accedere a un metodo o campo, oppure si utilizza [per indicizzare un array.

Se si tenta di dereferenziare numPRIMA di creare l'oggetto, si ottiene un file NullPointerException. Nei casi più banali, il compilatore rileverà il problema e ti farà sapere che " num may not have been initialized," ma a volte potresti scrivere codice che non crea direttamente l'oggetto.

Ad esempio, potresti avere un metodo come segue:

public void doSomething(SomeObject obj) {
   //do something to obj
}

In tal caso, non si crea l'oggetto obj, ma si presume che sia stato creato prima della doSomething()chiamata del metodo. Nota, è possibile chiamare il metodo in questo modo:

doSomething(null);

In tal caso, objè null. Se il metodo ha lo scopo di fare qualcosa all'oggetto passato, è appropriato lanciare il NullPointerExceptionperché è un errore del programmatore e il programmatore avrà bisogno di quelle informazioni per scopi di debug. Si prega di includere il nome della variabile oggetto nel messaggio di eccezione, come

Objects.requireNonNull(a, "a");

In alternativa, potrebbero esserci casi in cui lo scopo del metodo non è esclusivamente quello di operare sull'oggetto passato e quindi un parametro nullo può essere accettabile. In questo caso, dovresti verificare la presenza di un parametro nullo e comportarti in modo diverso. Dovresti anche spiegarlo nella documentazione. Ad esempio, doSomething()potrebbe essere scritto come:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj == null) {
       //do something
    } else {
       //do something else
    }
}

Infine, come individuare l'eccezione e la causa utilizzando Stack Trace

Quali metodi / strumenti possono essere utilizzati per determinare la causa in modo da impedire all'eccezione di causare la chiusura anticipata del programma?

Il sonar con bug di ricerca può rilevare NPE. Il sonar può rilevare eccezioni di puntatore nullo causate da JVM dinamicamente

Ora Java 14 ha aggiunto una nuova funzionalità del linguaggio per mostrare la causa principale di NullPointerException. Questa funzionalità del linguaggio fa parte della JVM commerciale di SAP dal 2006. Quanto segue è una lettura di 2 minuti per comprendere questa straordinaria funzionalità del linguaggio.

https://jfeatures.com/blog/NullPointerException

In java 14 il seguente è un messaggio di eccezione NullPointerException di esempio:

nel thread "main" java.lang.NullPointerException: Impossibile richiamare "java.util.List.size ()" perché "list" è nullo


572
"Il modo migliore per evitare questo tipo di eccezione è controllare sempre la presenza di null quando non hai creato tu stesso l'oggetto." Se il chiamante passa null, ma null non è un argomento valido per il metodo, è corretto restituire l'eccezione al chiamante perché è colpa del chiamante. Ignorare silenziosamente input non validi e non fare nulla nel metodo è un consiglio estremamente scarso perché nasconde il problema.
Boann

107
Vorrei aggiungere un'osservazione su questo post spiegando che anche gli assegnamenti alle primitive possono causare NPE quando si utilizza l'autoboxing: int a=bpuò generare un NPE se b è un Integer. Ci sono casi in cui è difficile eseguire il debug.
Simon Fischer

61
È possibile acquisire l'NPE lanciato da un'app Web dal browser Web? Come verrà mostrato nella pagina di visualizzazione sorgente dal browser Web ..
Sid

79
Sì, controlla se l'oggetto è uguale a null prima di invocare un metodo su di esso o prova ad accedere a una variabile che potrebbe avere. Alcune volte strutturare il codice può aiutare a evitare l'eccezione del puntatore nullo. ad esempio, quando si controlla una stringa di input con una stringa costante, è necessario iniziare con la stringa costante come qui: if ("SomeString" .equals (inputString)) {} // anche se inputString è null non viene generata alcuna eccezione. Quindi ci sono un sacco di cose che puoi fare per cercare di essere al sicuro.
Rose

81
Un altro modo per evitare NullPointerExceptionproblemi nel codice è quello di utilizzare @Nullablee @NotNullannotazioni. La seguente risposta contiene ulteriori informazioni su questo. Sebbene questa risposta riguardi specificamente l'IDE IntelliJ, è applicabile anche ad altri strumenti come l'apparenza dai commenti. (A proposito, non sono autorizzato a modificare direttamente questa risposta, forse l'autore può aggiungerla?)
Arjan Mels

897

NullPointerExceptionLe s sono eccezioni che si verificano quando si tenta di utilizzare un riferimento che non punta a nessuna posizione in memoria (null) come se stesse facendo riferimento a un oggetto. La chiamata a un metodo su un riferimento null o il tentativo di accedere a un campo di un riferimento null attiverà un NullPointerException. Questi sono i più comuni, ma altri modi sono elencati nella NullPointerExceptionpagina javadoc.

Probabilmente il codice di esempio più veloce che potrei inventare per illustrare un NullPointerExceptionsarebbe:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

Nella prima riga interna main, imposto esplicitamente il Objectriferimento objuguale a null. Ciò significa che ho un riferimento, ma non punta a nessun oggetto. Dopodiché, provo a trattare il riferimento come se puntasse a un oggetto chiamando un metodo su di esso. Ciò si traduce in un NullPointerExceptionperché non c'è codice da eseguire nella posizione che punta il riferimento.

(Questo è un tecnicismo, ma penso che valga la pena menzionarlo: un riferimento che punta a null non è lo stesso di un puntatore C che punta a una posizione di memoria non valida. Un puntatore null non punta letteralmente da nessuna parte , il che è leggermente diverso da che punta a una posizione che sembra non essere valida.)


50
Ho capito tutto ciò che hai scritto lì, ma solo perché ho scritto codice per un po 'e so cosa sono un "puntatore" e un "riferimento" (e cosa è null, se è per questo). Quando cerco di immergermi direttamente in spiegazioni del genere, i miei studenti mi guardano strabici, perché non c'è abbastanza background.
mmr

34
@mmr: grazie per il feedback, fai un punto valido. È difficile su Internet giudicare veramente dove si trova qualcuno ea quale livello è sicuro iniziare una spiegazione. Proverò a rivederlo di nuovo.
Bill the Lizard

23
Un modo più comune per ottenere una NullPointerException in pratica sarebbe dimenticare di inizializzare esplicitamente una variabile membro su qualcosa di diverso da nullprima di usarla, come questo . Con le variabili locali, il compilatore rileva questo errore, ma in questo caso no. Forse sarebbe un'utile aggiunta alla tua risposta?
Ilmari Karonen

7
@EJP Penso che i tuoi punti siano validi, quindi ho aggiornato la risposta per essere più chiara e per evitare di dire "punti a null" dove era.
Steve Powell

6
@StevePowell Ho indicato molto tempo fa che non volevo che la mia risposta cambiasse. Si prega di rispettare l'intento dell'autore originale.
Bill the Lizard

708

Cos'è una NullPointerException?

Un buon punto di partenza è JavaDocs . Hanno questo coperto:

Generato quando un'applicazione tenta di utilizzare null nel caso in cui è richiesto un oggetto. Questi includono:

  • Chiamata al metodo di istanza di un oggetto null.
  • Accesso o modifica del campo di un oggetto nullo.
  • Prendendo la lunghezza di null come se fosse un array.
  • Accedere o modificare gli slot di null come se fosse un array.
  • Lanciare null come se fosse un valore Throwable.

Le applicazioni dovrebbero generare istanze di questa classe per indicare altri usi illegali dell'oggetto null.

È anche il caso che se si tenta di utilizzare un riferimento nullo con synchronized, verrà generata anche questa eccezione, per JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Altrimenti, se il valore di Expression è null, NullPointerExceptionviene generato a.

Come lo aggiusto?

Quindi hai un file NullPointerException. Come lo aggiusti? Facciamo un semplice esempio che genera un NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Identifica i valori nulli

Il primo passo è identificare esattamente quali valori stanno causando l'eccezione . Per questo, dobbiamo fare un po 'di debug. È importante imparare a leggere uno stacktrace . Questo ti mostrerà dove è stata generata l'eccezione:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Qui, vediamo che l'eccezione viene lanciata sulla riga 13 (nel printStringmetodo). Guarda la riga e controlla quali valori sono nulli aggiungendo istruzioni di registrazione o utilizzando un debugger . Scopriamo che sè nullo e la chiamata al lengthmetodo su di esso genera l'eccezione. Possiamo vedere che il programma smette di lanciare l'eccezione quando s.length()viene rimosso dal metodo.

Traccia da dove provengono questi valori

Quindi controlla da dove proviene questo valore. Seguendo i chiamanti del metodo, vediamo che sviene passato con printString(name)nel print()metodo ed this.nameè nullo.

Traccia dove dovrebbero essere impostati questi valori

Dov'è this.nameambientato? Nel setName(String)metodo. Con un po 'più di debug, possiamo vedere che questo metodo non viene chiamato affatto. Se il metodo è stato chiamato, assicurati di controllare l' ordine in cui vengono chiamati questi metodi e il metodo set non viene chiamato dopo il metodo print.

Questo è sufficiente per darci una soluzione: aggiungi una chiamata a printer.setName()prima di chiamare printer.print().

Altre correzioni

La variabile può avere un valore predefinito (e setNamepuò impedire che venga impostata su null):

private String name = "";

Il metodo printo printStringpuò verificare la presenza di null , ad esempio:

printString((name == null) ? "" : name);

Oppure puoi progettare la classe in modo che name abbia sempre un valore non nullo :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

Guarda anche:

Non riesco ancora a trovare il problema

Se hai provato a eseguire il debug del problema e non hai ancora una soluzione, puoi pubblicare una domanda per ulteriore assistenza, ma assicurati di includere ciò che hai provato finora. Come minimo, includi lo stacktrace nella domanda e contrassegna i numeri di riga importanti nel codice. Inoltre, prova prima a semplificare il codice (vedi SSCCE ).


46
+1 Buono per avere un esempio che includa passare attraverso lo stacktrace; è importante mostrare perché leggerlo è importante per il debug di NPE. (e perché cerchiamo quasi sempre uno stacktrace quando qualcuno posta una domanda su un errore)
Dennis Meng,

18
Hai menzionato il debugging ... Come funziona? Sto cercando l'argomento da un po 'di tempo, ma non riesco a trovare nulla. Sono sicuro che un insegnante straordinario come te può insegnarmelo in un secondo! Grazie mille! :-)
Ruchir Baronia

17
@RuchirBaronia Un debugger ti consente di scorrere un programma riga per riga per vedere quali metodi vengono chiamati e come vengono modificate le variabili. Gli IDE dovrebbero avere alcuni strumenti per farlo. Vedi vogella.com/tutorials/EclipseDebugging/article.html per esempio.
fgb

17
@RuchirBaronia Imposta i punti di interruzione sui metodi attorno a qualsiasi NullPointerExceptions come mostrato nello stacktrace e controlla i valori delle variabili rispetto a ciò che ti aspetti che siano. Se sai che una variabile è nulla quando non dovrebbe esserlo, puoi impostare punti di interruzione attorno a qualsiasi codice che modifichi il valore. Ci sono anche punti di interruzione condizionali che puoi usare che ti diranno quando un valore cambia.
fgb

4
suggerisco anche strumenti di analisi statica, come FINDBUGS en.m.wikipedia.org/wiki/FindBugs
Massimo

515

Domanda: cosa causa un NullPointerException(NPE)?

Come dovreste sapere, tipi Java sono divisi in tipi primitivi ( boolean, int, ecc) e tipi di riferimento . I tipi di riferimento in Java consentono di utilizzare il valore speciale nullche è il modo Java di dire "nessun oggetto".

A NullPointerExceptionviene lanciato in fase di esecuzione ogni volta che il programma tenta di utilizzare a nullcome se fosse un riferimento reale. Ad esempio, se scrivi questo:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

l'istruzione etichettata "HERE" tenterà di eseguire il length()metodo su un nullriferimento e questo genererà un file NullPointerException.

Esistono molti modi per utilizzare un nullvalore che risulterà in un file NullPointerException. In effetti, le uniche cose che puoi fare con un nullsenza causare un NPE sono:

  • assegnarlo a una variabile di riferimento o leggerlo da una variabile di riferimento,
  • assegnarlo a un elemento dell'array o leggerlo da un elemento dell'array (a condizione che il riferimento all'array stesso non sia nullo!),
  • passarlo come parametro o restituirlo come risultato, o
  • testarlo utilizzando gli ==o !=operatori, o instanceof.

Domanda: come leggo lo stacktrace NPE?

Supponiamo che io compili ed esegua il programma sopra:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

Prima osservazione: la compilazione riesce! Il problema nel programma NON è un errore di compilazione. È un errore di runtime . (Alcuni IDE potrebbero avvertire che il tuo programma genererà sempre un'eccezione ... ma il javaccompilatore standard no.)

Seconda osservazione: quando eseguo il programma, emette due righe di "gobbledy-gook". SBAGLIATO!! Non è gobbledy-gook. È uno stacktrace ... e fornisce informazioni vitali che ti aiuteranno a rintracciare l'errore nel tuo codice se ti prendi il tempo di leggerlo attentamente.

Quindi diamo un'occhiata a cosa dice:

Exception in thread "main" java.lang.NullPointerException

La prima riga della traccia dello stack ti dice una serie di cose:

  • Ti dice il nome del thread Java in cui è stata generata l'eccezione. Per un programma semplice con un thread (come questo), sarà "main". Andiamo avanti ...
  • Ti dice il nome completo dell'eccezione che è stata lanciata; cioè java.lang.NullPointerException.
  • Se l'eccezione ha un messaggio di errore associato, verrà emesso dopo il nome dell'eccezione. NullPointerExceptionè insolito in questo senso, perché raramente ha un messaggio di errore.

La seconda riga è la più importante nella diagnosi di un NPE.

at Test.main(Test.java:4)

Questo ci dice una serie di cose:

  • "at Test.main" dice che eravamo nel mainmetodo della Testclasse.
  • "Test.java:4" fornisce il nome del file sorgente della classe, E ci dice che l'istruzione in cui si è verificato è nella riga 4 del file.

Se conti le righe nel file sopra, la riga 4 è quella che ho etichettato con il commento "QUI".

Nota che in un esempio più complicato, ci saranno molte righe nella traccia dello stack NPE. Ma puoi essere certo che la seconda riga (la prima riga "at") ti dirà dove è stato lanciato l'NPE 1 .

In breve, la traccia dello stack ci dirà in modo inequivocabile quale affermazione del programma ha generato l'NPE.

1 - Non proprio vero. Ci sono cose chiamate eccezioni annidate ...

Domanda: come faccio a rintracciare la causa dell'eccezione NPE nel mio codice?

Questa è la parte difficile. La risposta breve è applicare l'inferenza logica all'evidenza fornita dalla traccia dello stack, dal codice sorgente e dalla documentazione API pertinente.

Illustriamo prima con il semplice esempio (sopra). Iniziamo osservando la riga che la traccia dello stack ci ha detto è dove si è verificato l'NPE:

int length = foo.length(); // HERE

Come può generare un NPE?

In effetti, c'è un solo modo: può accadere solo se fooha il valore null. Proviamo quindi a eseguire il length()metodo nulle ... BANG!

Ma (ti sento dire) cosa succederebbe se l'NPE fosse stato lanciato all'interno della length()chiamata al metodo?

Bene, se ciò accadesse, la traccia dello stack apparirebbe diversa. La prima riga "at" direbbe che l'eccezione è stata lanciata in una riga della java.lang.Stringclasse e la riga 4 di Test.javasarebbe la seconda riga "at".

Allora da dove nullviene? In questo caso, è ovvio ed è ovvio cosa dobbiamo fare per risolverlo. (Assegna un valore non nullo a foo.)

OK, quindi proviamo un esempio leggermente più complicato. Ciò richiederà una deduzione logica .

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

Quindi ora abbiamo due righe "at". Il primo è per questa linea:

return args[pos].length();

e il secondo è per questa linea:

int length = test(foo, 1);

Guardando la prima riga, come potrebbe generare un NPE? Ci sono due modi:

  • Se il valore di barè nullquindi bar[pos]lancerà un NPE.
  • Se il valore di bar[pos]è nullquindi invitante length(), genererà un NPE.

Successivamente, dobbiamo capire quale di questi scenari spiega cosa sta realmente accadendo. Inizieremo esplorando il primo:

Da dove barviene? È un parametro per la testchiamata al metodo e se guardiamo come è teststato chiamato, possiamo vedere che proviene dalla foovariabile statica. Inoltre, possiamo vedere chiaramente che abbiamo inizializzato foosu un valore non nullo. Ciò è sufficiente per respingere provvisoriamente questa spiegazione. (In teoria, qualcos'altro potrebbe cambiare foo in null... ma questo non sta accadendo qui.)

E il nostro secondo scenario? Bene, possiamo vedere che posè 1, quindi significa che foo[1]deve essere null. È possibile?

Certo che lo è! E questo è il problema. Quando inizializziamo in questo modo:

private static String[] foo = new String[2];

assegniamo a String[]con due elementi che vengono inizializzatinull . Dopodiché, non abbiamo cambiato il contenuto di foo... così foo[1]sarà ancora null.


432

È come se stessi cercando di accedere a un oggetto che è null. Considera l'esempio seguente:

TypeA objA;

A questo punto hai appena dichiarato questo oggetto ma non è stato inizializzato o istanziato . E ogni volta che provi ad accedere a qualsiasi proprietà o metodo al suo interno, verrà visualizzato il messaggio NullPointerExceptionche ha senso.

Vedi anche questo esempio sotto:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

2
Se diamo System.out.println (a.length ()); // Verrà generata un'eccezione NullPointerException, per ignorarla possiamo gestirla con il blocco try catch. grazie
Vijaya Varma Lanke

365

Viene generata un'eccezione del puntatore null quando un'applicazione tenta di utilizzare null in un caso in cui è richiesto un oggetto. Questi includono:

  1. Chiamata al metodo di istanza di un nulloggetto.
  2. Accesso o modifica del campo di un nulloggetto.
  3. Prendendo la lunghezza di nullcome se fosse un array.
  4. Accedere o modificare gli slot di nullcome se fosse un array.
  5. Lanciare nullcome se fosse un valore Lanciabile.

Le applicazioni dovrebbero generare istanze di questa classe per indicare altri usi illegali nulldell'oggetto.

Riferimento: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html


13
Sii semplice, questa risposta mi piace, aggiungila se ritieni corretto - Accesso all'attributo non inizializzato di un oggetto
Emiliano

6
@Emiliano - il semplice accesso a un attributo inizializzato non causa un NPE. È ciò che >> fai << con il valore dell'attributo non inizializzato che causa l'NPE.
Stephen C

2
Se vuoi più casi: 1) usando a nullcome target di un synchronizedblocco, 2) usando a nullcome target di a switch, e unboxing null.
Stephen C

340

Un nullpuntatore è quello che punta a nulla. Quando si dereferenzia un puntatore p, si dice "dammi i dati nella posizione memorizzata in" p ". Quando pè un nullpuntatore, la posizione memorizzata in pè nowhere, stai dicendo" dammi i dati nella posizione 'da nessuna parte' ". Ovviamente, non può farlo, quindi genera un null pointer exception.

In generale, è perché qualcosa non è stato inizializzato correttamente.


5
"Un puntatore NULL è quello che non punta a nulla" Non sono d'accordo. I puntatori nulli non puntano a nulla, puntano a valori nulli.
TheRealChx101

329

Sono già presenti molte spiegazioni per spiegare come accade e come risolverlo, ma dovresti anche seguire le migliori pratiche per evitare NullPointerExceptiondel tutto.

Vedi anche: Un buon elenco di best practice

Aggiungerei, molto importante, fare un buon uso del finalmodificatore. Utilizzo del modificatore "finale" ogniqualvolta applicabile in Java

Sommario:

  1. Usa il finalmodificatore per imporre una buona inizializzazione.
  2. Evita di restituire null nei metodi, ad esempio restituendo raccolte vuote quando applicabile.
  3. Usa annotazioni @NotNulle@Nullable
  4. Fallisci velocemente e usa asserts per evitare la propagazione di oggetti nulli attraverso l'intera applicazione quando non dovrebbero essere nulli.
  5. Usa prima uguale con un oggetto noto: if("knownObject".equals(unknownObject)
  6. Preferiscono valueOf()sopra toString().
  7. Utilizza StringUtilsmetodi null safe StringUtils.isEmpty(null).
  8. Usa Java 8 Optional come valore di ritorno nei metodi, la classe Optional fornisce una soluzione per rappresentare valori facoltativi invece di riferimenti nulli.

5
Nei progetti j2ee, l'eccezione Nullpointer è molto comune.Alcuni casi le variabili di riferimento hanno valori nulli, quindi dovresti controllare correttamente l'inizializzazione delle variabili e durante l'istruzione condizionale dovresti sempre controllare che il flag o il riferimento contenga null o non come: - if (flag! = 0) {ur code that uses flag}
Amaresh Pattanayak

15
Vale la pena ricordare che alcuni IDE (ad es. Eclipse) offrono un'analisi automatica della nullità basata su annotazioni personalizzabili (ad es. @NullableCome elencato sopra) e avvisano di potenziali errori. È anche possibile dedurre e generare tali annotazioni (es. IntelliJ può farlo) in base alla struttura del codice esistente.
Jan Chimiak

4
La prima cosa da fare è prima di usare un oggetto nullable, dovresti controllare se è nullo, usando if (obj==null).Se è nullo allora dovresti scrivere il codice per gestire anche quello.
Lakmal Vithanage

4
IMO, è preferibile evitare di restituire oggetti nulli nei metodi quando possibile e utilizzare l'annotazione quando i parametri di input nulli non sono consentiti al fine di, per contratto, ridurre la quantità di ´if (obj == null) ´ nel codice e migliorare il leggibilità del codice.
LG

4
Leggi questo ... prima di accettare queste "best practice" come verità: satisfaction.com/blog/archives/27
Stephen C

323

In Java, tutto (esclusi i tipi primitivi) ha la forma di una classe.

Se vuoi usare qualsiasi oggetto, hai due fasi:

  1. Dichiarare
  2. Inizializzazione

Esempio:

  • Dichiarazione: Object object;
  • Inizializzazione: object = new Object();

Lo stesso per il concetto di array:

  • Dichiarazione: Item item[] = new Item[5];
  • Inizializzazione: item[0] = new Item();

Se non stai dando la sezione di inizializzazione, allora il NullPointerExceptionsorgere.


4
Una NullPointerException si verifica spesso quando si chiama il metodo di un'istanza. Ad esempio, se si dichiara un riferimento ma non lo si fa puntare a nessuna istanza, NullPointerException si verificherà quando si chiama il suo metodo. ad esempio: YourClass ref = null; // o ref = anotherRef; // ma anotherRef non ha puntato alcuna istanza ref.someMethod (); // lancerà NullPointerException. In genere risolverlo in questo modo: prima di chiamare il metodo, determinare se il riferimento è nullo. come: if (yourRef! = null) {yourRef.someMethod (); }
Sunhang

3
Oppure usa la cattura delle eccezioni: come: try {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
sunhang


322

Un'eccezione del puntatore nullo è un indicatore che stai utilizzando un oggetto senza inizializzarlo.

Ad esempio, di seguito è riportata una classe di studenti che la utilizzerà nel nostro codice.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Il codice seguente ti dà un'eccezione del puntatore nullo.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Perché stai usando student, ma hai dimenticato di inizializzarlo come nel codice corretto mostrato di seguito:

public class School {

    Student student;

    public School() {
        try {
            student = new Student();
            student.setId(12);
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

9
Anche se questo è un bell'esempio, posso chiedere cosa aggiunge alla domanda che non è già coperta da tutte le altre risposte?
Mysticial

15
È semplicemente inappropriato utilizzare la parola "non inizializzato" qui. L'esempio mostrato è infatti "inizializzato" e viene inizializzato con null. Per le variabili non inizializzate, il compilatore si lamenterà con te.
Adrian Shum

315

In Java tutte le variabili dichiarate sono in realtà "riferimenti" agli oggetti (o primitive) e non agli oggetti stessi.

Quando si tenta di eseguire un metodo oggetto, il riferimento chiede all'oggetto vivente di eseguire quel metodo. Ma se il riferimento fa riferimento a NULL (niente, zero, void, nada), non è possibile che il metodo venga eseguito. Quindi il runtime ti fa sapere questo lanciando una NullPointerException.

Il tuo riferimento "punta" a null, quindi "Null -> Pointer".

L'oggetto risiede nello spazio di memoria della VM e l'unico modo per accedervi è utilizzare i thisriferimenti. Prendi questo esempio:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

E in un altro punto del codice:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Questa è una cosa importante da sapere - quando non ci sono più riferimenti a un oggetto (nell'esempio sopra quando referenceed otherReferenceentrambi puntano a null) allora l'oggetto è "irraggiungibile". Non è possibile lavorarci sopra, quindi questo oggetto è pronto per essere sottoposto a garbage collection e, a un certo punto, la VM libererà la memoria utilizzata da questo oggetto e ne assegnerà un altro.


287

Un'altra occorrenza di a si NullPointerExceptionverifica quando si dichiara un array di oggetti, quindi si cerca immediatamente di dereferenziare gli elementi al suo interno.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Questa particolare NPE può essere evitata invertendo l'ordine di confronto; vale a dire, l'uso .equalssu un oggetto non nullo garantito.

Tutti gli elementi all'interno di un array vengono inizializzati al loro valore iniziale comune ; per qualsiasi tipo di array di oggetti, ciò significa che tutti gli elementi lo sono null.

È necessario inizializzare gli elementi nell'array prima di accedervi o dereferenziarli.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

1
l'operazione su un oggetto non inizializzato a livello di istanza (non a livello di classe) porterà a NullPointerException. l'operazione deve essere specifica dell'istanza. se l'operazione è a livello di classe, dicendo che si chiama un metodo statico su un oggetto non inizializzato, non verrà generata l'eccezione NullPointerException. Anche gli oggetti di classe wrapper primitivi generano NullPointerException.
Shailendra Singh

1
1. NullPointerException è una RuntimeException, il che significa che apparirà quando il tuo programma è in esecuzione, non al momento della compilazione.! :(, ma la maggior parte dell'IDE ti aiuta a scoprirlo. 2. Riduci al minimo l'uso della parola chiave "null" nelle istruzioni di assegnazione. :) URL di riferimento:
tomj0101

1
@ tomj0101 Non sono completamente chiaro sul motivo per cui hai fatto quel commento ... Ma per il tuo secondo punto, uno schema prima Optionalera di restituire null. La parola chiave va bene. Sapere come proteggersi è fondamentale. Questo offre un evento comune e modi per mitigarlo.
Makoto

1
NullPointerException è un'eccezione in fase di esecuzione che non è consigliabile rilevarla , ma invece evitarla.
Shomu

4
@ Shomu: A che punto suggerisco di catturarlo?
Makoto
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.