Apa itu Pengecualian Pointer Null (java.lang.NullPointerException
) dan apa penyebabnya?
Metode/alat apa yang bisa digunakan untuk menentukan penyebabnya sehingga anda bisa menghentikan pengecualian yang menyebabkan program terhenti sebelum waktunya?
Ketika anda mendeklarasikan reference variable (yaitu objek) anda benar-benar menciptakan sebuah pointer ke objek. Perhatikan kode berikut dimana anda mendeklarasikan variabel dari tipe primitif int
:
int x;
x = 10;
Dalam contoh ini, variabel x
adalah sebuah int
dan Jawa akan menginisialisasi ke 0
untuk anda. Bila anda menetapkan nilai 10
pada baris kedua, anda nilai 10
dituliskan ke dalam lokasi memori yang disebut dengan x
.
Tapi, ketika anda mencoba untuk mendeklarasikan reference tipe, sesuatu yang berbeda terjadi. Mengambil kode berikut:
Integer num;
num = new Integer(10);
Baris pertama menyatakan sebuah variabel bernama num
, tapi itu tidak benar-benar mengandung primitif nilai belum. Sebaliknya, berisi pointer (karena jenis ini Integer
yang merupakan tipe referensi). Karena anda belum mengatakan apa untuk menunjukkan, Java set ke null
, yang berarti "aku menunjuk ke ada".
Di baris kedua, baru
kata kunci yang digunakan untuk instantiate (atau membuat) suatu objek dari jenis Integer
dan pointer variabel bil
ditugaskan untuk itu Integer
objek.
The NullPointerException
terjadi ketika anda mendeklarasikan sebuah variabel, tetapi tidak membuat sebuah objek. Jadi anda menunjuk ke sesuatu yang sebenarnya tidak ada.
Jika anda mencoba untuk dereference num
SEBELUM membuat objek anda mendapatkan NullPointerException
. Dalam kebanyakan kasus sepele, compiler akan menangkap masalah dan membiarkan anda tahu bahwa "num mungkin belum diinisialisasi
," tapi 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 menciptakan objek obj
, melainkan dengan asumsi bahwa itu diciptakan sebelum melakukan sesuatu()
metode ini disebut. Catatan, itu adalah mungkin untuk memanggil metode seperti ini:
doSomething(null);
Dalam hal ini, obj
adalah null
. Jika metode ini dimaksudkan untuk melakukan sesuatu untuk lulus-objek, adalah tepat untuk membuang NullPointerException
karena itu's programmer kesalahan dan programmer akan membutuhkan informasi tersebut untuk keperluan debugging.
Atau, mungkin ada kasus di mana tujuan dari metode ini adalah tidak semata-mata untuk beroperasi pada lulus dalam objek, dan oleh karena itu null parameter yang dapat diterima. Dalam hal ini, anda akan perlu untuk memeriksa null parameter dan berperilaku berbeda. Anda juga harus menjelaskan hal ini di dokumentasi. Misalnya, melakukan sesuatu()
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, Cara untuk menentukan pengecualian & menyebabkan menggunakan Stack Trace
NullPointerException
adalah pengecualian yang terjadi ketika Anda mencoba menggunakan referensi yang tidak menunjuk ke lokasi dalam memori (null) seolah-olah referensi itu merujuk ke sebuah objek. Memanggil metode pada referensi null atau mencoba mengakses field dari referensi null akan memicu NullPointerException
. Ini adalah yang paling umum, tetapi cara-cara lain tercantum pada halaman javadoc NullPointerException
.
Mungkin contoh kode tercepat yang bisa saya buat untuk mengilustrasikan NullPointerException
adalah:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
Pada baris pertama di dalam main
, saya secara eksplisit mengatur referensi Object
obj
sama dengan null
. Ini berarti saya memiliki referensi, tetapi tidak menunjuk ke objek apapun. Setelah itu, saya mencoba memperlakukan referensi seolah-olah menunjuk ke sebuah objek dengan memanggil sebuah metode di atasnya. Ini menghasilkan NullPointerException
karena tidak ada kode yang bisa dieksekusi di lokasi yang ditunjuk oleh referensi.
(Ini adalah teknis, tetapi saya pikir ini perlu disebutkan: Sebuah referensi yang menunjuk ke null tidak sama dengan pointer C yang menunjuk ke lokasi memori yang tidak valid. Sebuah pointer null secara harfiah tidak menunjuk ke mana-mana, yang secara halus berbeda dengan menunjuk ke lokasi yang kebetulan tidak valid).
Tempat yang baik untuk memulai adalah JavaDocs. Mereka telah tertutup ini:
Dilemparkan ketika sebuah aplikasi mencoba untuk menggunakan null pada kasus di mana suatu objek diperlukan. Ini termasuk:
- Panggilan-contoh metode dari objek yang kosong.
- Mengakses atau memodifikasi bidang objek yang kosong.
- Mengambil panjang null seolah-olah itu sebuah array.
- Mengakses atau memodifikasi slot null seolah-olah itu sebuah array.
- Lempar null seolah-olah itu adalah Throwable nilai.
Aplikasi harus membuang contoh dari kelas ini untuk menunjukkan lain penggunaan ilegal dari objek null.
Hal ini juga terjadi bahwa jika anda mencoba untuk menggunakan null referensi dengan sinkron
, yang juga akan melempar pengecualian ini, per JLS:
SynchronizedStatement: disinkronisasi ( Ekspresi ) Blok
- Sebaliknya, jika nilai Ekspresi null,
NullPointerException
dilemparkan.
Jadi anda memiliki NullPointerException
. Bagaimana cara anda memperbaikinya? Let's 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();
}
}
Mengidentifikasi nilai-nilai null
Langkah pertama adalah mengidentifikasi dengan tepat nilai-nilai yang menyebabkan pengecualian. Untuk ini, kita perlu melakukan beberapa debugging. It's penting untuk belajar membaca a stacktrace. Ini akan menunjukkan anda 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 on line 13 (di printString
method). Melihat garis dan cek yang nilai null dengan
menambahkan penebangan pernyataan atau menggunakan debugger. Kita mengetahui bahwa s
adalah nol, dan memanggil panjang
cara melempar pengecualian. Kita dapat melihat bahwa program berhenti melemparkan pengecualian ketika s.length()
dihapus dari metode.
Melacak di mana nilai-nilai ini berasal dari
Cek berikutnya di mana nilai ini berasal dari. Dengan mengikuti penelepon dari metode ini, kita melihat bahwa s
ini berlalu dengan printString(nama)
di print()
metode ini.nama
adalah null.
Melacak di mana nilai-nilai ini harus ditetapkan
Dimana ini.nama
set? Di setName(String)
metode. Dengan beberapa lebih debugging, kita dapat melihat bahwa metode ini isn't disebut sama sekali. Jika metode tersebut dipanggil, pastikan untuk memeriksa order bahwa metode ini disebut, dan menetapkan metode isn't disebut setelah metode cetak.
Ini sudah cukup untuk memberikan kita solusi: tambahkan panggilan untuk printer.setName()
sebelum memanggil printer.cetak()
.
Variabel dapat memiliki nilai default (dan setName
dapat mencegah hal ini sedang diatur untuk null):
private String name = "";
Baik cetak
atau printString
metode memeriksa null, misalnya:
printString((name == null) ? "" : name);
Atau anda dapat merancang kelas sehingga nama
selalu memiliki nilai non-null:
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();
}
}
Baca juga:
Jika anda mencoba untuk men-debug masalah dan masih don't memiliki solusi, anda dapat memposting pertanyaan untuk bantuan lebih lanjut, tetapi pastikan untuk memasukkan apa yang anda'sudah mencoba sejauh ini. Minimal, termasuk stacktrace dalam pertanyaan, dan mark penting nomor baris dalam kode. Juga, mencoba menyederhanakan kode pertama (lihat SSCCE).
NullPointerException
(NPE)? Seperti yang anda harus tahu, Jawa jenis dibagi menjadi tipe primitif (boolean
, int
, dll.) dan jenis referensi. Referensi jenis di Jawa memungkinkan anda untuk menggunakan nilai khusus null
yang merupakan Java cara untuk mengatakan "tidak ada objek".
A NullPointerException
dilemparkan pada saat runtime setiap kali program anda mencoba untuk menggunakan null
seolah-olah itu adalah nyata referensi. Misalnya, jika anda menulis ini:
public class Test {
public static void main(String[] args) {
String foo = null;
int length = foo.length(); // HERE
}
}
pernyataan berlabel "di SINI" akan mencoba untuk menjalankan panjang ()
pada metode null
referensi, dan hal ini akan membuang NullPointerException
.
Ada banyak cara yang bisa anda gunakan nilai "null" yang akan menghasilkan NullPointerException
. Pada kenyataannya, satu-satunya hal yang anda ** bisa dilakukan dengan null
tanpa menyebabkan NPE adalah:
==
atau !=
operator, atau instanceof
.
Pertanyaan: Bagaimana cara membaca NPE stacktrace? 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 ini BUKAN kesalahan kompilasi. Ini adalah runtime kesalahan. (Beberapa Ide dapat memperingatkan anda program akan selalu melempar pengecualian ... tapi standar javac
compiler doesn't.)
Pengamatan kedua: ketika saya menjalankan program, ini menghasilkan dua baris "sulit dipahami". SALAH!! Yang's tidak sulit dipahami. Itu adalah jejak stack ... dan menyediakan informasi penting yang akan membantu anda melacak kesalahan dalam kode anda, jika anda mengambil waktu untuk membaca dengan hati-hati.
Jadi let's melihat apa yang dikatakan:
Exception in thread "main" java.lang.NullPointerException
Baris pertama dari stack trace memberitahu anda beberapa hal:
jawa.lang.NullPointerException
. NullPointerException
adalah yang tidak biasa dalam hal ini, karena hal itu jarang memiliki pesan kesalahan.
Baris kedua adalah salah satu yang paling penting dalam mendiagnosis NPE. at Test.main(Test.java:4)
Ini memberitahu kita beberapa hal:
main
metode Test
kelas. Ini adalah bagian yang sulit. Jawaban singkatnya adalah untuk menerapkan kesimpulan logis untuk bukti yang diberikan oleh stack trace, source code dan API yang relevan dokumentasi. Let's menggambarkan dengan contoh sederhana (atas) pertama. Kita mulai dengan melihat garis yang stack trace telah memberitahu kita di mana NPE terjadi:
int length = foo.length(); // HERE
Bagaimana bisa membuang NPE?
Dalam kenyataannya hanya ada satu cara: itu hanya bisa terjadi jika foo
memiliki nilai null
. Kami kemudian mencoba untuk menjalankan panjang ()
metode null
dan .... BANG!
Tapi (saya mendengar anda berkata) bagaimana jika NPE dilemparkan dalam panjang ()
metode panggilan?
Nah, jika itu terjadi, stack akan terlihat berbeda. Pertama "di" line akan mengatakan bahwa pengecualian dilemparkan dalam beberapa baris di pulau jawa.lang.Stringkelas, dan baris 4
Test.javaakan menjadi yang kedua "di" garis. Jadi mana yang
nullberasal? Dalam hal ini jelas, dan hal ini jelas apa yang perlu kita lakukan untuk memperbaikinya. (Menetapkan nilai non-null untuk
foo`.)
OK, jadi let's mencoba sedikit lebih rumit contoh. Ini akan membutuhkan beberapa deduksi 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 "di" garis-garis. Yang pertama adalah untuk baris ini:
return args[pos].length();
dan yang kedua adalah untuk baris ini:
int length = test(foo, 1);
Melihat baris pertama, bagaimana itu bisa membuang NPE? Ada dua cara:
bar
adalah null
kemudian bar[pos]
akan membuang NPE. bar[pos]
adalah null
kemudian memanggil panjang ()
pada itu akan membuang NPE.
Selanjutnya, kita perlu untuk mengetahui mana dari skenario tersebut menjelaskan apa yang sebenarnya terjadi. Kita akan mulai dengan menjelajahi pertama:
Mana bar
berasal? Ini adalah sebuah parameter untuk menguji
metode panggilan, dan jika kita melihat bagaimana test
yang disebut, kita dapat melihat bahwa itu berasal dari foo
variabel statis. Selain itu, kita dapat melihat dengan jelas bahwa kita diinisialisasi foo
dengan nilai non-null. Itu sudah cukup untuk sementara mengabaikan penjelasan ini. (Dalam teori, sesuatu yang lain bisa perubahan foo
untuk null
... tapi itu tidak terjadi di sini.)
Sehingga apa yang kami kedua skenario? Nah, kita dapat melihat bahwa pos
adalah 1
, jadi itu berarti bahwa foo[1]
harus null
. Itu mungkin?
Memang hal ini! Dan itu adalah masalah. Ketika kita menginisialisasi seperti ini: private static String[] foo = new String[2];
kami mengalokasikan String[]
dengan dua elemen yang diinisialisasi untuk null
. Setelah itu, kami belum mengubah isi foo
... jadi foo[1]
masih akan null
.
Ini seperti Anda mencoba mengakses objek yang null
. Perhatikan contoh di bawah ini:
TypeA objA;
Pada saat ini Anda baru saja mendeklarasikan objek ini tetapi tidak diinisialisasi atau diinstansiasi. Dan setiap kali Anda mencoba mengakses properti atau metode apa pun di dalamnya, itu akan melemparkan NullPointerException
yang masuk akal.
Lihat contoh di bawah ini juga:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Null pointer exception dilemparkan ketika sebuah aplikasi mencoba untuk menggunakan null dalam kasus di mana sebuah objek yang diperlukan. Ini termasuk:
nol
objek.null
objek.null
seolah-olah itu sebuah array.null
seolah-olah itu sebuah array.null
seolah-olah itu adalah Throwable nilai. Aplikasi harus membuang contoh dari kelas ini untuk menunjukkan penggunaan ilegal lainnya dari nol
objek.
Referensi: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
Pointer null
adalah pointer yang tidak menunjuk ke mana-mana. Ketika anda melakukan dereference sebuah pointer p
, anda mengatakan "berikan saya data di lokasi yang tersimpan di "p". Ketika p
adalah pointer null
, lokasi yang tersimpan di p
adalah nowhere
, anda mengatakan "berikan saya data di lokasi 'nowhere'". Jelas, ia tidak bisa melakukan ini, sehingga ia melempar pointer nol pengecualian
.
Secara umum, itu karena ada sesuatu yang belum diinisialisasi dengan benar.
Banyak penjelasan yang sudah hadir untuk menjelaskan bagaimana hal itu terjadi dan bagaimana untuk memperbaikinya, tetapi anda juga harus mengikuti praktek-praktek terbaik untuk menghindari `NullPointerException itu sama sekali.
Lihat juga: Daftar yang baik dari praktek-praktek terbaik
Saya akan menambahkan, sangat penting, membuat baik penggunaan final
modifier.
https://stackoverflow.com/questions/137868/using-final-modifier-whenever-applicable-in-java
Ringkasan:
final
modifier untuk menegakkan yang baik inisialisasi.@NotNull
dan @Nullable
jika("knownObject".sama dengan(unknownObject)
valueOf()
atas toString().StringUtils
metode StringUtils.isEmpty(null)
.Null pointer exception merupakan indikator bahwa anda menggunakan sebuah objek tanpa memulainya.
Sebagai contoh, di bawah ini adalah siswa kelas yang akan digunakan 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 memberikan anda null pointer exception.
public class School {
Student student;
public School() {
try {
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
Karena anda menggunakan mahasiswa
, tapi anda lupa untuk menginisialisasi seperti di
memperbaiki kode 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, segala sesuatu (termasuk tipe primitif) adalah dalam bentuk kelas.
Jika anda ingin menggunakan objek apapun maka anda memiliki dua fase:
Contoh:
Objek objek;
object = new Object();
Yang sama untuk array konsep:
Item Item[] = new Item[5];
item[0] = new Item();
Jika anda tidak memberikan inisialisasi bagian kemudian NullPointerException
muncul.
Di Jawa semua variabel yang anda menyatakan yang sebenarnya "referensi" benda-benda (atau primitif) dan bukan obyek itu sendiri.
Ketika anda mencoba untuk mengeksekusi satu objek metode, referensi meminta hidup objek untuk menjalankan metode tersebut. Tapi jika referensi adalah referensi NULL (tidak ada, nol, kosong, nada) maka tidak ada metode yang akan dieksekusi. Kemudian runtime membiarkan anda tahu ini dengan melempar NullPointerException.
Situs referensi "menunjuk" untuk null, dengan demikian "Null -> Pointer".
Objek tinggal di VM ruang memori dan satu-satunya cara untuk mengaksesnya adalah dengan menggunakan ini
referensi. 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 suatu hal yang penting untuk tahu - ketika tidak ada lebih banyak referensi untuk sebuah objek (dalam contoh di atas ketika referensi
dan otherReference
kedua titik nol) maka objek adalah "terjangkau". Tidak ada cara kita dapat bekerja dengan itu, sehingga objek ini siap menjadi sampah yang dikumpulkan, dan di beberapa titik, VM akan membebaskan memori yang digunakan oleh objek ini dan akan mengalokasikan lain.
Lain terjadinya NullPointerException
terjadi ketika seseorang menyatakan suatu objek array, kemudian segera mencoba untuk dereference unsur-unsur di dalamnya.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
khusus Ini NPE dapat dihindari jika perbandingan urutan terbalik; yaitu, gunakan .sama dengan
jaminan non-null objek.
Semua elemen di dalam sebuah array diinisialisasi untuk umum mereka nilai awal; untuk setiap jenis objek array, yang berarti bahwa semua elemen null
.
Anda harus menginisialisasi elemen dalam array sebelum mengakses atau dereferencing mereka.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}