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 x
adalah int
dan Java akan menginisialisasi 0
untuk Anda. Ketika Anda menetapkan nilai 10
pada baris kedua, nilai Anda 10
ditulis 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 Integer
tipe referensi). Karena Anda belum mengatakan apa yang harus ditunjukkan , Java mengaturnya null
, yang berarti " Saya tidak menunjuk apa - apa ".
Di baris kedua, new
kata kunci digunakan untuk instantiate (atau membuat) objek bertipe Integer
dan variabel pointer num
ditugaskan ke Integer
objek itu.
Itu NullPointerException
terjadi 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 num
SEBELUM 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, obj
adalah null
. Jika metode ini dimaksudkan untuk melakukan sesuatu ke objek yang lewat, itu tepat untuk melempar NullPointerException
karena 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=b
NPE saat menggunakan autoboxing: dapat melempar NPE jika b adalahInteger
. Ada kasus di mana ini membingungkan untuk debug.NullPointerException
masalah dalam kode Anda adalah dengan menggunakan@Nullable
dan@NotNull
anotasi. 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?)NullPointerException
s 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 aNullPointerException
. Ini adalah yang paling umum, tetapi cara lain terdaftar di InternetNullPointerException
halaman javadoc.Mungkin contoh kode tercepat yang dapat saya berikan untuk menggambarkan
NullPointerException
adalah:Pada baris pertama di dalam
main
, saya secara eksplisit menetapkanObject
referensiobj
sama dengannull
. 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.)
sumber
null
sebelum 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?Apa itu NullPointerException?
Tempat yang baik untuk memulai adalah JavaDocs . Mereka memiliki ini meliputi:
Ini juga merupakan kasus bahwa jika Anda mencoba menggunakan referensi nol
synchronized
, itu juga akan membuang pengecualian ini, sesuai JLS :Bagaimana saya memperbaikinya?
Jadi, Anda punya
NullPointerException
. Bagaimana Anda memperbaikinya? Mari kita ambil contoh sederhana yang melemparNullPointerException
: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:
Di sini, kita melihat bahwa pengecualian dilemparkan pada baris 13 (dalam
printString
metode). Lihatlah baris dan periksa nilai-nilai mana yang nol dengan menambahkan pernyataan logging atau menggunakan debugger . Kami menemukan bahwas
itu nol, dan memanggillength
metode di atasnya melempar pengecualian. Kita dapat melihat bahwa program berhenti melempar pengecualian ketikas.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
s
diteruskan denganprintString(name)
dalamprint()
metode ini, danthis.name
nol.Lacak di mana nilai-nilai ini harus ditetapkan
Di mana
this.name
diatur? DalamsetName(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 memanggilprinter.print()
.Perbaikan lainnya
Variabel dapat memiliki nilai default (dan
setName
dapat mencegahnya disetel ke nol):Entah metode
print
atauprintString
dapat memeriksa nol , misalnya:Atau Anda bisa mendesain kelas sehingga
name
selalu memiliki nilai bukan nol :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 ).
sumber
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
NullPointerException
dilempar pada saat runtime setiap kali program Anda mencoba menggunakannull
seolah-olah itu adalah referensi nyata. Misalnya, jika Anda menulis ini:pernyataan yang berlabel "DI SINI" akan mencoba menjalankan
length()
metode padanull
referensi, dan ini akan membuang aNullPointerException
.Ada banyak cara Anda bisa menggunakan
null
nilai yang akan menghasilkan aNullPointerException
. Faktanya, satu-satunya hal yang dapat Anda lakukan dengannull
tanpa menyebabkan NPE adalah:==
atau!=
operator, atauinstanceof
.Pertanyaan: Bagaimana saya membaca stacktrace NPE?
Misalkan saya mengkompilasi dan menjalankan program di atas:
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 standar
javac
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:
Baris pertama jejak tumpukan memberi tahu Anda beberapa hal:
java.lang.NullPointerException
.NullPointerException
tidak biasa dalam hal ini, karena jarang memiliki pesan kesalahan.Baris kedua adalah yang paling penting dalam mendiagnosis NPE.
Ini memberi tahu kita beberapa hal:
main
metodeTest
kelas.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:
Bagaimana itu bisa melempar NPE?
Padahal, hanya ada satu cara: itu hanya bisa terjadi jika
foo
punya nilainull
. Kami kemudian mencoba menjalankanlength()
metodenull
dan ... 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.String
kelas dan baris 4Test.java
akan menjadi baris "at" kedua.Jadi dari mana
null
asalnya? Dalam hal ini, jelas, dan jelas apa yang perlu kita lakukan untuk memperbaikinya. (Tetapkan nilai bukan nol kefoo
.)OK, jadi mari kita coba contoh yang sedikit lebih rumit. Ini akan membutuhkan beberapa pengurangan logis .
Jadi sekarang kita memiliki dua garis "at". Yang pertama untuk baris ini:
dan yang kedua untuk baris ini:
Melihat baris pertama, bagaimana itu bisa melempar NPE? Ada dua cara:
bar
ininull
makabar[pos]
akan melempar NPE.bar[pos]
ininull
kemudian memanggilnyalength()
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 untuktest
pemanggilan metode, dan jika kita melihat bagaimanatest
dipanggil, kita dapat melihat bahwa itu berasal darifoo
variabel statis. Selain itu, kita dapat melihat dengan jelas bahwa kita diinisialisasifoo
ke nilai yang bukan nol. Itu cukup untuk sementara menolak penjelasan ini. (Secara teori, sesuatu yang lain bisa berubahfoo
menjadinull
... tapi itu tidak terjadi di sini.)Jadi bagaimana dengan skenario kedua kita? Nah, kita dapat melihat bahwa
pos
adalah1
, sehingga berarti bahwafoo[1]
harusnull
. Apakah ini mungkin?Memang itu! Dan itu masalahnya. Ketika kita menginisialisasi seperti ini:
kami mengalokasikan
String[]
dengan dua elemen yang diinisialisasi kenull
. Setelah itu, kami belum mengubah kontenfoo
... jadifoo[1]
akan tetap demikiannull
.sumber
Ini seperti Anda mencoba mengakses objek yang ada
null
. Pertimbangkan contoh di bawah ini: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
NullPointerException
yang masuk akal.Lihat contoh di bawah ini juga:
sumber
Pengecualian null pointer dilemparkan ketika aplikasi mencoba menggunakan null dalam kasus di mana objek diperlukan. Ini termasuk:
null
objek.null
objek.null
seolah-olah array.null
seolah-olah array.null
seolah-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
sumber
null
sebagai targetsynchronized
blok, 2) menggunakannull
sebagai sebagai target dariswitch
, dan unboxingnull
.Sebuah
null
pointer adalah salah satu yang poin ke mana-mana. Ketika Anda dereference pointerp
, Anda mengatakan "memberi saya data di lokasi yang disimpan di 'p'. Ketikap
adalahnull
pointer, lokasi disimpan dalamp
adalahnowhere
, Anda mengatakan 'memberi saya data di lokasi 'tempat''. Jelas, itu tidak bisa melakukan ini, jadi itu melempar anull pointer exception
.Secara umum, itu karena sesuatu belum diinisialisasi dengan benar.
sumber
NULL
ditulis sepertinull
dalam 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
NullPointerException
sama sekali.Lihat juga: Daftar praktik terbaik yang baik
Saya akan menambahkan, sangat penting, manfaatkan
final
pengubah. Menggunakan pengubah "final" kapan pun berlaku di JawaRingkasan:
final
pengubah untuk menegakkan inisialisasi yang baik.@NotNull
dan@Nullable
if("knownObject".equals(unknownObject)
valueOf()
lebihtoString()
.StringUtils
metode aman nolStringUtils.isEmpty(null)
.sumber
@Nullable
seperti 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
NullPointerException
muncul.sumber
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.
Kode di bawah ini memberi Anda pengecualian null pointer.
Karena Anda menggunakan
student
, tetapi Anda lupa untuk menginisialisasi seperti dalam kode yang benar yang ditunjukkan di bawah ini:sumber
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
this
referensi. Ambil contoh ini:Dan di tempat lain dalam kode Anda:
Ini hal yang penting untuk diketahui - ketika tidak ada lagi referensi ke suatu objek (dalam contoh di atas kapan
reference
danotherReference
keduanya 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.sumber
Kejadian lain dari suatu
NullPointerException
terjadi ketika seseorang menyatakan array objek, kemudian segera mencoba untuk meringkas elemen di dalamnya.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 adalah
null
.Anda harus menginisialisasi elemen dalam array sebelum mengakses atau mereferensikannya.
sumber
Optional
adalah mengembalikan nol. Kata kuncinya baik-baik saja. Mengetahui bagaimana cara menjaganya tidak penting. Ini menawarkan satu kejadian umum dan cara untuk menguranginya.