Apa itu NullPointerException, dan bagaimana cara memperbaikinya?

210

Apa itu Pengecualian Null Pointer ( java.lang.NullPointerException) dan apa yang menyebabkannya?

Metode / alat apa yang dapat digunakan untuk menentukan penyebabnya sehingga Anda menghentikan pengecualian dari menyebabkan program berakhir sebelum waktunya?

Ziggy
sumber

Jawaban:

3766

Ketika Anda mendeklarasikan variabel referensi (yaitu objek), Anda benar-benar membuat pointer ke objek. Pertimbangkan kode berikut di mana Anda mendeklarasikan variabel tipe primitif int:

int x;
x = 10;

Dalam contoh ini, variabelnya xadalah intdan Java akan menginisialisasi 0untuk Anda. Ketika Anda menetapkan nilai 10pada baris kedua, nilai Anda 10ditulis ke dalam lokasi memori yang dirujuk oleh x.

Tetapi, ketika Anda mencoba untuk mendeklarasikan tipe referensi , sesuatu yang berbeda terjadi. Ambil kode berikut:

Integer num;
num = new Integer(10);

Baris pertama mendeklarasikan variabel bernama num, tetapi sebenarnya belum mengandung nilai primitif. Sebaliknya, ini berisi pointer (karena tipenya adalah Integertipe referensi). Karena Anda belum mengatakan apa yang harus ditunjukkan , Java mengaturnya null, yang berarti " Saya tidak menunjuk apa - apa ".

Di baris kedua, newkata kunci digunakan untuk instantiate (atau membuat) objek bertipe Integerdan variabel pointer numditugaskan ke Integerobjek itu.

Itu NullPointerExceptionterjadi ketika Anda mendeklarasikan variabel tetapi tidak membuat objek dan menetapkan ke variabel sebelum mencoba menggunakan konten variabel (disebut dereferencing ). Jadi Anda menunjuk sesuatu yang sebenarnya tidak ada.

Dereferencing biasanya terjadi ketika menggunakan .untuk mengakses metode atau bidang, atau menggunakan [untuk mengindeks array.

Jika Anda mencoba melakukan dereferensi numSEBELUM membuat objek yang Anda dapatkan NullPointerException. Dalam kasus yang paling sepele, kompiler akan menangkap masalah dan memberi tahu Anda bahwa " num may not have been initialized," tetapi kadang-kadang Anda dapat menulis kode yang tidak secara langsung membuat objek.

Misalnya, Anda mungkin memiliki metode sebagai berikut:

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

Dalam hal ini, Anda tidak membuat objek obj, tetapi dengan asumsi bahwa itu dibuat sebelum doSomething()metode dipanggil. Catatan, adalah mungkin untuk memanggil metode seperti ini:

doSomething(null);

Dalam hal ini, objadalah null. Jika metode ini dimaksudkan untuk melakukan sesuatu ke objek yang lewat, itu tepat untuk melempar NullPointerExceptionkarena itu adalah kesalahan pemrogram dan pemrogram akan membutuhkan informasi itu untuk keperluan debugging. Harap sertakan nama variabel objek dalam pesan pengecualian, seperti

Objects.requireNonNull(a, "a");

Atau, mungkin ada kasus-kasus di mana tujuan metode ini tidak semata-mata untuk beroperasi pada objek yang diteruskan, dan oleh karena itu parameter nol dapat diterima. Dalam hal ini, Anda perlu memeriksa parameter nol dan berperilaku berbeda. Anda juga harus menjelaskan ini dalam dokumentasi. Misalnya, doSomething()dapat ditulis sebagai:

/**
  * @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
    }
}

Akhirnya, Bagaimana menentukan pengecualian & penyebab menggunakan Stack Trace

Metode / alat apa yang dapat digunakan untuk menentukan penyebabnya sehingga Anda menghentikan pengecualian dari menyebabkan program berakhir sebelum waktunya?

Sonar dengan findbugs dapat mendeteksi NPE. Dapat sonar menangkap pengecualian pointer nol yang disebabkan oleh JVM secara dinamis

Vincent Ramdhanie
sumber
558
"Cara terbaik untuk menghindari jenis pengecualian ini adalah dengan selalu memeriksa nol ketika Anda tidak membuat objek sendiri." Jika pemanggil melewati nol, tetapi nol bukan argumen yang valid untuk metode ini, maka itu benar untuk melemparkan kembali pengecualian pada pemanggil karena itu adalah kesalahan pemanggil. Diam-diam mengabaikan input yang tidak valid dan tidak melakukan apa pun dalam metode ini adalah saran yang sangat buruk karena menyembunyikan masalahnya.
Boann
104
Saya akan menambahkan komentar tentang posting ini menjelaskan bahwa bahkan penugasan untuk primitif dapat menyebabkan int a=bNPE saat menggunakan autoboxing: dapat melempar NPE jika b adalah Integer. Ada kasus di mana ini membingungkan untuk debug.
Simon Fischer
58
Apakah mungkin untuk menangkap NPE yang dilemparkan oleh webapp dari browser web? Seperti apakah itu akan ditampilkan di sumber halaman tampilan dari browser web ..
Sid
76
Ya, periksa apakah objek sama dengan nol sebelum Anda memanggil metode atau mencoba mengakses variabel yang mungkin ada. Beberapa kali menyusun kode Anda dapat membantu menghindari pengecualian null pointer. misal ketika memeriksa string input dengan string konstan, Anda harus mulai dengan string konstan seperti di sini: if ("SomeString" .equals (inputString)) {} // bahkan jika inputString adalah null, tidak ada pengecualian yang dilemparkan. Jadi ada banyak hal yang dapat Anda lakukan untuk mencoba menjadi aman.
Rose
78
Cara tambahan untuk menghindari NullPointerExceptionmasalah dalam kode Anda adalah dengan menggunakan @Nullabledan @NotNullanotasi. Jawaban berikut memiliki informasi lebih lanjut tentang ini. Meskipun jawaban ini khusus tentang IDE IntelliJ, ini juga berlaku untuk alat lain seperti yang mungkin dari komentar. (BTW saya tidak diizinkan mengedit jawaban ini secara langsung, mungkin penulis dapat menambahkannya?)
Arjan Mels
880

NullPointerExceptions adalah pengecualian yang terjadi ketika Anda mencoba menggunakan referensi yang menunjuk ke tidak ada lokasi dalam memori (nol) seolah-olah itu merujuk objek. Memanggil metode pada referensi nol atau mencoba mengakses bidang referensi nol akan memicu a NullPointerException. Ini adalah yang paling umum, tetapi cara lain terdaftar di InternetNullPointerException halaman javadoc.

Mungkin contoh kode tercepat yang dapat saya berikan untuk menggambarkan NullPointerExceptionadalah:

public class Example {

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

}

Pada baris pertama di dalam main, saya secara eksplisit menetapkan Objectreferensi objsama dengan null. Ini berarti saya memiliki referensi, tetapi tidak menunjuk ke objek apa pun. Setelah itu, saya mencoba untuk memperlakukan referensi seolah-olah menunjuk ke suatu objek dengan memanggil metode di atasnya. Ini menghasilkan aNullPointerException karena tidak ada kode untuk dieksekusi di lokasi yang ditunjuk oleh referensi.

(Ini adalah masalah teknis, tapi saya rasa perlu disebutkan: Referensi yang menunjuk ke nol tidak sama dengan pointer C yang menunjuk ke lokasi memori yang tidak valid. Sebuah pointer nol secara harfiah tidak menunjuk ke mana pun , yang secara subtil berbeda dari menunjuk ke lokasi yang tidak valid.)

Bill the Lizard
sumber
49
Saya mengerti semua yang Anda tulis di sana, tetapi hanya karena saya telah mengkode untuk sementara waktu dan tahu apa 'pointer' dan 'referensi' (dan apa null, dalam hal ini). Ketika saya mencoba menyelami penjelasan seperti itu, murid-murid saya melihat saya bersilang, karena tidak ada latar belakang yang cukup.
mmr
33
@ mmr: Terima kasih atas umpan baliknya, Anda membuat poin yang valid. Sulit di internet untuk benar-benar menilai di mana seseorang berada, dan pada tingkat apa aman untuk memulai penjelasan. Saya akan mencoba merevisi ini lagi.
Bill the Lizard
22
Cara yang lebih umum untuk mendapatkan NullPointerException dalam praktiknya akan lupa untuk secara eksplisit menginisialisasi variabel anggota ke sesuatu selain nullsebelum menggunakannya, seperti ini . Dengan variabel lokal, kompiler akan menangkap kesalahan ini, tetapi dalam kasus ini tidak. Mungkin itu akan menjadi tambahan yang berguna untuk jawaban Anda?
Ilmari Karonen
6
@ EJP Saya pikir poin Anda valid, jadi saya telah memperbarui jawabannya menjadi lebih jelas dan untuk menghindari mengatakan 'poin ke nol' di mana itu terjadi.
Steve Powell
5
@StevePowell Saya sudah lama menunjukkan bahwa saya tidak ingin jawaban saya berubah. Harap hormati maksud penulis asli.
Bill the Lizard
697

Apa itu NullPointerException?

Tempat yang baik untuk memulai adalah JavaDocs . Mereka memiliki ini meliputi:

Dilemparkan ketika aplikasi mencoba menggunakan null dalam kasus di mana objek diperlukan. Ini termasuk:

  • Memanggil metode instance dari objek null.
  • Mengakses atau memodifikasi bidang objek nol.
  • Mengambil panjang nol seolah-olah array.
  • Mengakses atau memodifikasi slot nol seolah-olah array.
  • Melempar nol seolah-olah itu adalah nilai yang bisa dibuang.

Aplikasi harus membuang instance kelas ini untuk menunjukkan penggunaan ilegal lainnya dari objek nol.

Ini juga merupakan kasus bahwa jika Anda mencoba menggunakan referensi nol synchronized, itu juga akan membuang pengecualian ini, sesuai JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Kalau tidak, jika nilai Ekspresi adalah nol, a NullPointerExceptiondilemparkan.

Bagaimana saya memperbaikinya?

Jadi, Anda punya NullPointerException. Bagaimana Anda memperbaikinya? Mari kita ambil contoh sederhana yang melempar 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();
    }
}

Identifikasi nilai nol

Langkah pertama adalah mengidentifikasi dengan tepat nilai mana yang menyebabkan pengecualian . Untuk ini, kita perlu melakukan debugging. Sangat penting untuk belajar membaca stacktrace . Ini akan menunjukkan di mana pengecualian dilemparkan:

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)

Di sini, kita melihat bahwa pengecualian dilemparkan pada baris 13 (dalam printStringmetode). Lihatlah baris dan periksa nilai-nilai mana yang nol dengan menambahkan pernyataan logging atau menggunakan debugger . Kami menemukan bahwa situ nol, dan memanggil lengthmetode di atasnya melempar pengecualian. Kita dapat melihat bahwa program berhenti melempar pengecualian ketika s.length()dihapus dari metode.

Lacak dari mana nilai-nilai ini berasal

Selanjutnya periksa dari mana nilai ini berasal. Dengan mengikuti penelepon metode, kita melihat bahwa sditeruskan dengan printString(name)dalam print()metode ini, dan this.namenol.

Lacak di mana nilai-nilai ini harus ditetapkan

Di mana this.namediatur? Dalam setName(String)metode. Dengan lebih banyak debugging, kita dapat melihat bahwa metode ini tidak dipanggil sama sekali. Jika metode dipanggil, pastikan untuk memeriksa urutan metode ini dipanggil, dan metode yang ditetapkan tidak dipanggil setelah metode cetak.

Ini cukup untuk memberi kami solusi: tambahkan panggilan printer.setName()sebelum memanggil printer.print().

Perbaikan lainnya

Variabel dapat memiliki nilai default (dan setNamedapat mencegahnya disetel ke nol):

private String name = "";

Entah metode printatau printStringdapat memeriksa nol , misalnya:

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

Atau Anda bisa mendesain kelas sehingga name selalu memiliki nilai bukan nol :

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();
    }
}

Lihat juga:

Saya masih tidak dapat menemukan masalahnya

Jika Anda mencoba men-debug masalah dan masih belum memiliki solusi, Anda dapat memposting pertanyaan untuk bantuan lebih lanjut, tetapi pastikan untuk memasukkan apa yang telah Anda coba sejauh ini. Minimal, sertakan stacktrace dalam pertanyaan, dan tandai nomor baris penting dalam kode. Juga, cobalah menyederhanakan kode terlebih dahulu (lihat SSCCE ).

fgb
sumber
44
+1 Bagus untuk memiliki contoh yang mencakup menelusuri stacktrace; penting untuk menunjukkan mengapa membaca itu penting untuk debugging NPE. (dan mengapa kami hampir selalu mencari stacktrace ketika seseorang memposting pertanyaan tentang kesalahan)
Dennis Meng
16
Anda menyebutkan debugging ... Bagaimana cara kerjanya? Saya telah meneliti topik ini untuk sementara waktu sekarang, tetapi tidak dapat menemukan apa pun. Saya yakin guru yang luar biasa seperti Anda bisa mengajarkannya kepada saya dalam hitungan detik! Terima kasih banyak! :-)
Ruchir Baronia
15
@RuchirBaronia Seorang debugger memungkinkan Anda untuk melangkah melalui program baris demi baris untuk melihat metode mana yang dipanggil dan bagaimana variabel diubah. IDE harus memiliki beberapa alat untuk melakukan ini. Lihat vogella.com/tutorials/EclipseDebugging/article.html misalnya.
fgb
15
@RuchirBaronia Anda menetapkan breakpoint pada metode di sekitar NullPointerExceptions seperti yang terlihat di stacktrace, dan periksa nilai variabel terhadap apa yang Anda harapkan. Jika Anda tahu suatu variabel adalah nol padahal seharusnya tidak, maka Anda bisa mengatur breakpoint di sekitar kode apa pun yang mengubah nilainya. Ada juga breakpoint bersyarat yang bisa Anda gunakan yang akan memberi tahu Anda ketika suatu nilai berubah.
fgb
6
Mengatur objek String ke string kosong karena nilai defaultnya dianggap sebagai praktik yang buruk.
Tiny
502

Pertanyaan: Apa yang menyebabkan a NullPointerException (NPE)?

Seperti yang Anda ketahui, jenis Java dibagi menjadi tipe primitif ( boolean, int, dll) dan jenis referensi . Jenis referensi di Jawa memungkinkan Anda untuk menggunakan nilai khususnull yang merupakan cara Java untuk mengatakan "tidak ada objek".

A NullPointerExceptiondilempar pada saat runtime setiap kali program Anda mencoba menggunakan nullseolah-olah itu adalah referensi nyata. Misalnya, jika Anda menulis ini:

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

pernyataan yang berlabel "DI SINI" akan mencoba menjalankan length()metode pada nullreferensi, dan ini akan membuang aNullPointerException .

Ada banyak cara Anda bisa menggunakan nullnilai yang akan menghasilkan a NullPointerException. Faktanya, satu-satunya hal yang dapat Anda lakukan dengan nulltanpa menyebabkan NPE adalah:

  • menugaskannya ke variabel referensi atau membacanya dari variabel referensi,
  • menugaskannya ke elemen array atau membacanya dari elemen array (asalkan referensi array itu sendiri bukan nol!),
  • kirimkan sebagai parameter atau kembalikan sebagai hasilnya, atau
  • mengujinya menggunakan ==atau !=operator, atau instanceof.

Pertanyaan: Bagaimana saya membaca stacktrace NPE?

Misalkan saya mengkompilasi dan menjalankan program di atas:

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

Pengamatan pertama: kompilasi berhasil! Masalah dalam program BUKAN kesalahan kompilasi. Ini adalah kesalahan runtime . (Beberapa IDE mungkin memperingatkan program Anda akan selalu mengeluarkan pengecualian ... tetapi standarjavac kompiler tidak.)

Pengamatan kedua: ketika saya menjalankan program, ini menghasilkan dua baris "gobbledy-gook". SALAH!! Itu bukan gobbledy-gook. Ini adalah stacktrace ... dan memberikan informasi penting yang akan membantu Anda melacak kesalahan dalam kode Anda jika Anda meluangkan waktu untuk membacanya dengan cermat.

Jadi mari kita lihat apa yang dikatakannya:

Exception in thread "main" java.lang.NullPointerException

Baris pertama jejak tumpukan memberi tahu Anda beberapa hal:

  • Ini memberi tahu Anda nama utas Java tempat pengecualian dilemparkan. Untuk program sederhana dengan satu utas (seperti ini), itu akan menjadi "utama". Mari kita lanjutkan ...
  • Ini memberi tahu Anda nama lengkap pengecualian yang dilemparkan; yaitu java.lang.NullPointerException.
  • Jika pengecualian memiliki pesan kesalahan yang terkait, itu akan menjadi output setelah nama pengecualian. NullPointerExceptiontidak biasa dalam hal ini, karena jarang memiliki pesan kesalahan.

Baris kedua adalah yang paling penting dalam mendiagnosis NPE.

at Test.main(Test.java:4)

Ini memberi tahu kita beberapa hal:

  • "at Test.main" mengatakan bahwa kami menggunakan mainmetode Testkelas.
  • "Test.java:4" memberikan nama file sumber kelas, DAN itu memberi tahu kita bahwa pernyataan di mana ini terjadi adalah di baris 4 file.

Jika Anda menghitung baris dalam file di atas, baris 4 adalah yang saya beri label dengan komentar "DI SINI".

Perhatikan bahwa dalam contoh yang lebih rumit, akan ada banyak baris dalam jejak tumpukan NPE. Tapi Anda bisa yakin bahwa baris kedua (baris "at" pertama) akan memberi tahu Anda di mana NPE dilempar 1 .

Singkatnya, jejak stack akan memberi tahu kita dengan jelas pernyataan program mana yang telah melemparkan NPE.

1 - Tidak sepenuhnya benar. Ada hal-hal yang disebut pengecualian bersarang ...

Pertanyaan: Bagaimana cara melacak penyebab pengecualian NPE dalam kode saya?

Ini bagian yang sulit. Jawaban singkatnya adalah untuk menerapkan inferensi logis pada bukti yang diberikan oleh jejak stack, kode sumber, dan dokumentasi API yang relevan.

Mari kita ilustrasikan dengan contoh sederhana (di atas) terlebih dahulu. Kita mulai dengan melihat garis yang diceritakan jejak stack kepada kita adalah di mana NPE terjadi:

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

Bagaimana itu bisa melempar NPE?

Padahal, hanya ada satu cara: itu hanya bisa terjadi jika foopunya nilai null. Kami kemudian mencoba menjalankan length()metode nulldan ... BANG!

Tapi (saya dengar Anda bilang) bagaimana jika NPE dilemparkan ke dalam length()pemanggilan metode?

Nah, jika itu terjadi, jejak stack akan terlihat berbeda. Baris "at" pertama akan mengatakan bahwa eksepsi dilemparkan pada beberapa baris di java.lang.Stringkelas dan baris 4 Test.javaakan menjadi baris "at" kedua.

Jadi dari mana nullasalnya? Dalam hal ini, jelas, dan jelas apa yang perlu kita lakukan untuk memperbaikinya. (Tetapkan nilai bukan nol ke foo.)

OK, jadi mari kita coba contoh yang sedikit lebih rumit. Ini akan membutuhkan beberapa pengurangan logis .

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)
$ 

Jadi sekarang kita memiliki dua garis "at". Yang pertama untuk baris ini:

return args[pos].length();

dan yang kedua untuk baris ini:

int length = test(foo, 1);

Melihat baris pertama, bagaimana itu bisa melempar NPE? Ada dua cara:

  • Jika nilai barini nullmaka bar[pos]akan melempar NPE.
  • Jika nilai bar[pos]ini nullkemudian memanggilnya length()akan melempar NPE.

Selanjutnya, kita perlu mencari tahu skenario mana yang menjelaskan apa yang sebenarnya terjadi. Kami akan mulai dengan menjelajahi yang pertama:

Dari mana datangnya bar? Ini adalah parameter untuk testpemanggilan metode, dan jika kita melihat bagaimana testdipanggil, kita dapat melihat bahwa itu berasal dari foovariabel statis. Selain itu, kita dapat melihat dengan jelas bahwa kita diinisialisasi fooke nilai yang bukan nol. Itu cukup untuk sementara menolak penjelasan ini. (Secara teori, sesuatu yang lain bisa berubah foo menjadinull ... tapi itu tidak terjadi di sini.)

Jadi bagaimana dengan skenario kedua kita? Nah, kita dapat melihat bahwa posadalah 1, sehingga berarti bahwa foo[1]harus null. Apakah ini mungkin?

Memang itu! Dan itu masalahnya. Ketika kita menginisialisasi seperti ini:

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

kami mengalokasikan String[]dengan dua elemen yang diinisialisasi kenull . Setelah itu, kami belum mengubah konten foo... jadi foo[1]akan tetap demikian null.

Stephen C
sumber
426

Ini seperti Anda mencoba mengakses objek yang ada null. Pertimbangkan contoh di bawah ini:

TypeA objA;

Pada saat ini Anda baru saja mendeklarasikan objek ini tetapi tidak diinisialisasi atau dipakai . Dan setiap kali Anda mencoba mengakses properti atau metode apa pun di dalamnya, itu akan membuang NullPointerExceptionyang masuk akal.

Lihat contoh di bawah ini juga:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Rakesh Burbure
sumber
1
Jika kita memberikan System.out.println (a.length ()); // NullPointerException akan dilempar, untuk melewati ini kita dapat menangani dengan coba tangkap blok. terima kasih
Vijaya Varma Lanke
360

Pengecualian null pointer dilemparkan ketika aplikasi mencoba menggunakan null dalam kasus di mana objek diperlukan. Ini termasuk:

  1. Memanggil metode instance dari nullobjek.
  2. Mengakses atau memodifikasi bidang a null objek.
  3. Mengambil panjang null seolah-olah array.
  4. Mengakses atau memodifikasi slot null seolah-olah array.
  5. Melempar nullseolah-olah itu adalah nilai yang bisa dibuang.

Aplikasi harus membuang instance dari kelas ini untuk menunjukkan penggunaan ilegal lain dari null benda .

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

nathan1138
sumber
12
Sederhanakan, saya suka jawaban ini, tambahkan ini jika Anda anggap benar - Akses ke atribut objek yang tidak diinisialisasi
Emiliano
5
@ Emiliano - hanya mengakses atribut yang diinisialisasi tidak menyebabkan NPE. Inilah yang Anda >> lakukan << dengan nilai atribut tidak diinisialisasi yang menyebabkan NPE.
Stephen C
1
Jika Anda ingin lebih banyak kasus: 1) menggunakan nullsebagai target synchronizedblok, 2) menggunakan nullsebagai sebagai target dari switch, dan unboxing null.
Stephen C
334

Sebuah nullpointer adalah salah satu yang poin ke mana-mana. Ketika Anda dereference pointer p, Anda mengatakan "memberi saya data di lokasi yang disimpan di 'p'. Ketika padalah nullpointer, lokasi disimpan dalam padalah nowhere, Anda mengatakan 'memberi saya data di lokasi 'tempat''. Jelas, itu tidak bisa melakukan ini, jadi itu melempar a null pointer exception.

Secara umum, itu karena sesuatu belum diinisialisasi dengan benar.

MrZebra
sumber
2
Apakah kita membuat basis data? -> NULLditulis seperti nulldalam java. Dan itu hal yang sensitif.
bvdb
3
"Pointer NULL adalah salah satu yang menunjuk ke mana-mana" Saya tidak setuju. Pointer kosong tidak menunjuk ke mana-mana, mereka menunjuk ke nilai nol.
TheRealChx101
2
@ TheRealChx101 Penunjuk nol dan penunjuk ke nilai nol adalah hal yang berbeda - penunjuk nol tidak mengarah ke nilai nol. Misalkan Anda memiliki pointer ke pointer: pointer A menunjuk ke pointer B, dan pointer B adalah nol. Dalam hal ini, penunjuk A menunjuk ke nilai nol, dan penunjuk B adalah penunjuk nol.
MrZebra
322

Banyak penjelasan sudah ada untuk menjelaskan bagaimana itu terjadi dan bagaimana cara memperbaikinya, tetapi Anda juga harus mengikuti praktik terbaik untuk menghindari NullPointerExceptionsama sekali.

Lihat juga: Daftar praktik terbaik yang baik

Saya akan menambahkan, sangat penting, manfaatkan final pengubah. Menggunakan pengubah "final" kapan pun berlaku di Jawa

Ringkasan:

  1. Gunakan finalpengubah untuk menegakkan inisialisasi yang baik.
  2. Hindari pengembalian nol dalam metode, misalnya mengembalikan koleksi kosong jika ada.
  3. Gunakan anotasi @NotNulldan@Nullable
  4. Gagal cepat dan gunakan menegaskan untuk menghindari propagasi objek nol melalui seluruh aplikasi ketika mereka tidak boleh nol.
  5. Gunakan sama dengan objek yang dikenal pertama: if("knownObject".equals(unknownObject)
  6. Lebih valueOf()lebih toString().
  7. Gunakan StringUtilsmetode aman nol StringUtils.isEmpty(null).
  8. Gunakan Java 8 Opsional sebagai nilai balik dalam metode, kelas opsional menyediakan solusi untuk mewakili nilai opsional, bukan referensi nol.
LG
sumber
4
Dalam proyek j2ee, pengecualian Nullpointer sangat umum. Beberapa kasus variabel referensi mendapat nilai nol. Jadi Anda harus memeriksa inisialisasi variabel dengan benar. Dan selama pernyataan kondisional Anda harus selalu memeriksa bahwa flag atau referensi mengandung null atau tidak seperti: - if (flag! = 0) {kode Anda yang menggunakan flag}
Amaresh Pattanayak
14
Perlu disebutkan bahwa beberapa IDE (misalnya Eclipse) menawarkan analisis nullity otomatis berdasarkan anotasi yang dapat disesuaikan (misalnya @Nullableseperti yang tercantum di atas) dan memperingatkan tentang kemungkinan kesalahan. Dimungkinkan juga untuk menyimpulkan dan membuat anotasi semacam itu (mis. IntelliJ dapat melakukan itu) berdasarkan pada struktur kode yang ada.
Jan Chimiak
4
Hal pertama yang harus dilakukan adalah sebelum menggunakan objek nullable, Anda harus memeriksa apakah itu null, menggunakan if (obj==null). Jika itu null maka Anda harus menulis kode untuk mengatasinya juga.
Lakmal Vithanage
4
IMO, lebih baik untuk menghindari mengembalikan objek nol dalam metode bila memungkinkan dan menggunakan anotasi ketika parameter input nol tidak diizinkan untuk, dengan kontrak, mengurangi jumlah ´jika (obj == null) ´ dalam kode dan meningkatkan pembacaan kode.
LG
4
Baca ini ... sebelum Anda menerima "praktik terbaik" ini sebagai kebenaran: satisfice.com/blog/archives/27
Stephen C
317

Di Jawa, semuanya (tidak termasuk tipe primitif) adalah dalam bentuk kelas.

Jika Anda ingin menggunakan objek apa pun maka Anda memiliki dua fase:

  1. Menyatakan
  2. Inisialisasi

Contoh:

  • Pernyataan: Object object;
  • Inisialisasi: object = new Object();

Sama untuk konsep array:

  • Pernyataan: Item item[] = new Item[5];
  • Inisialisasi: item[0] = new Item();

Jika Anda tidak memberikan bagian inisialisasi maka NullPointerExceptionmuncul.

ashish bhatt
sumber
3
NullPointerException sering terjadi saat memanggil metode instance. Misalnya, jika Anda mendeklarasikan referensi tetapi tidak membuatnya menunjuk ke instance apa pun, NullPointerException akan terjadi ketika Anda memanggil metode tersebut. seperti: YourClass ref = null; // atau ref = anotherRef; // tapi anotherRef belum menunjuk instance ref.someMethod (); // itu akan melempar NullPointerException. Secara umum perbaiki dengan cara ini: Sebelum metode dipanggil, tentukan apakah referensi tersebut nol. seperti: if (yourRef! = null) {yourRef.someMethod (); }
sunhang
2
Atau gunakan penangkapan pengecualian: seperti: coba {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
sunhang
316

Pengecualian null pointer adalah indikator bahwa Anda menggunakan objek tanpa menginisialisasi itu.

Sebagai contoh, di bawah ini adalah kelas siswa yang akan menggunakannya dalam kode kita.

public class Student {

    private int id;

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

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

Kode di bawah ini memberi Anda pengecualian null pointer.

public class School {

    Student student;

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

Karena Anda menggunakan student, tetapi Anda lupa untuk menginisialisasi seperti dalam kode yang benar yang ditunjukkan di bawah ini:

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");
        }
    }
}
javid piprani
sumber
7
Meskipun ini adalah contoh yang bagus, bolehkah saya bertanya apa yang ditambahkan ke pertanyaan yang belum tercakup oleh semua jawaban lainnya?
Mysticial
13
Tidak tepat menggunakan kata "tidak diinisialisasi" di sini. Contoh yang Anda tunjukkan sebenarnya "diinisialisasi", dan itu diinisialisasi dengan nol. Untuk variabel yang tidak diinisialisasi, kompiler akan mengeluh kepada Anda.
Adrian Shum
2
NPE mungkin merupakan indikator bahwa Anda menggunakan bidang yang tidak diinisialisasi. Ini mungkin merupakan indikator bahwa Anda melakukan hal-hal lain. Menyederhanakan terlalu banyak penyebab tunggal seperti ini tidak membantu seseorang memecahkan masalah NPE ... jika penyebab sebenarnya bukan yang ini.
Stephen C
309

Di jawa semua variabel yang Anda nyatakan sebenarnya "referensi" ke objek (atau primitif) dan bukan objek itu sendiri.

Ketika Anda mencoba untuk mengeksekusi satu metode objek, referensi meminta objek hidup untuk mengeksekusi metode itu. Tetapi jika referensi merujuk NULL (tidak ada, nol, batal, nada) maka tidak ada cara metode dijalankan. Kemudian runtime memberi tahu Anda hal ini dengan melempar NullPointerException.

Referensi Anda adalah "menunjuk" ke nol, dengan demikian "Null -> Pointer".

Objek hidup di ruang memori VM dan satu-satunya cara untuk mengaksesnya adalah menggunakan thisreferensi. Ambil contoh ini:

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

Dan di tempat lain dalam kode Anda:

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...

Ini hal yang penting untuk diketahui - ketika tidak ada lagi referensi ke suatu objek (dalam contoh di atas kapan referencedan otherReferencekeduanya menunjuk ke nol) maka objek tersebut "tidak dapat dijangkau". Tidak ada cara kita dapat bekerja dengannya, jadi objek ini siap untuk dikumpulkan, dan pada titik tertentu, VM akan membebaskan memori yang digunakan oleh objek ini dan akan mengalokasikan yang lain.

OscarRyz
sumber
281

Kejadian lain dari suatu NullPointerExceptionterjadi ketika seseorang menyatakan array objek, kemudian segera mencoba untuk meringkas elemen di dalamnya.

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

NPE khusus ini dapat dihindari jika urutan perbandingan dibalik; yaitu, gunakan.equals pada objek non-null yang dijamin.

Semua elemen di dalam array diinisialisasi ke nilai awal bersama ; untuk semua jenis array objek, itu artinya semua elemen adalahnull .

Anda harus menginisialisasi elemen dalam array sebelum mengakses atau mereferensikannya.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}
Makoto
sumber
operasi pada objek yang tidak diinisialisasi pada level instance (bukan level kelas) akan mengarah ke NullPointerException. operasi harus spesifik instance. Jika operasi di tingkat kelas, mengatakan memanggil metode statis pada objek yang tidak diinisialisasi maka itu tidak akan membuang pengecualian NullPointerException. Bahkan objek kelas pembungkus primitif melempar NullPointerException.
Shailendra Singh
1. NullPointerException adalah RuntimeException, yang berarti akan muncul ketika program Anda berjalan, Anda tidak akan pada waktu kompilasi.! :(, tetapi sebagian besar IDE membantu Anda menemukan ini. 2. Minimalkan penggunaan kata kunci 'null' dalam pernyataan penugasan. :) Referensi url:
tomj0101
@ tomj0101 Saya sama sekali tidak jelas mengapa Anda membuat komentar itu ... Tapi ke poin kedua Anda, pola sebelumnya Optionaladalah mengembalikan nol. Kata kuncinya baik-baik saja. Mengetahui bagaimana cara menjaganya tidak penting. Ini menawarkan satu kejadian umum dan cara untuk menguranginya.
Makoto
NullPointerException adalah pengecualian run-time yang tidak disarankan untuk menangkapnya, melainkan menghindarinya.
Shomu
2
@ Shou: Pada titik apa saya bahkan menyarankan agar itu ditangkap?
Makoto