Jawaban:
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
int a=bNPE saat menggunakan autoboxing: dapat melempar NPE jika b adalah Integer. Ada kasus di mana ini membingungkan untuk debug.
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?)
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.)
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?
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.
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().
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:
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 ).
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:
==atau !=operator, atau instanceof.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:
java.lang.NullPointerException.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:
mainmetode Testkelas.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 ...
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:
barini nullmaka bar[pos]akan melempar NPE.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.
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
Pengecualian null pointer dilemparkan ketika aplikasi mencoba menggunakan null dalam kasus di mana objek diperlukan. Ini termasuk:
nullobjek.null objek.null seolah-olah array.null seolah-olah array.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
nullsebagai target synchronizedblok, 2) menggunakan nullsebagai sebagai target dari switch, dan unboxing null.
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.
NULLditulis seperti nulldalam java. Dan itu hal yang sensitif.
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:
finalpengubah untuk menegakkan inisialisasi yang baik.@NotNulldan@Nullableif("knownObject".equals(unknownObject)valueOf()lebih toString().StringUtilsmetode aman nol StringUtils.isEmpty(null).@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.
if (obj==null). Jika itu null maka Anda harus menulis kode untuk mengatasinya juga.
Di Jawa, semuanya (tidak termasuk tipe primitif) adalah dalam bentuk kelas.
Jika Anda ingin menggunakan objek apa pun maka Anda memiliki dua fase:
Contoh:
Object object;object = new Object();Sama untuk konsep array:
Item item[] = new Item[5];item[0] = new Item();Jika Anda tidak memberikan bagian inisialisasi maka NullPointerExceptionmuncul.
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");
}
}
}
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.
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));
}
Optionaladalah mengembalikan nol. Kata kuncinya baik-baik saja. Mengetahui bagaimana cara menjaganya tidak penting. Ini menawarkan satu kejadian umum dan cara untuk menguranginya.