Mengapa ini melempar NullPointerException
public static void main(String[] args) throws Exception {
Boolean b = true ? returnsNull() : false; // NPE on this line.
System.out.println(b);
}
public static Boolean returnsNull() {
return null;
}
sementara ini tidak
public static void main(String[] args) throws Exception {
Boolean b = true ? null : false;
System.out.println(b); // null
}
?
Solusinya adalah dengan cara mengganti false
dengan Boolean.FALSE
untuk menghindari null
unboxed ke boolean
- yang tidak mungkin. Tapi itu bukan pertanyaannya. Pertanyaannya adalah mengapa ? Apakah ada referensi di JLS yang mengkonfirmasi perilaku ini, terutama dari kasus ke-2?
Jawaban:
Perbedaannya adalah bahwa jenis eksplisit
returnsNull()
metode ini mempengaruhi pengetikan statis ekspresi pada waktu kompilasi:Lihat Spesifikasi Bahasa Jawa, bagian 15.25 Operator Bersyarat? :
Untuk E1, jenis operan ke-2 dan ke-3 adalah masing
Boolean
-boolean
masing, jadi klausa ini berlaku:Karena jenis ekspresinya adalah
boolean
, operan ke-2 harus dipaksaboolean
. Kompiler memasukkan kode buka-otomatis ke operan ke-2 (nilai balik darireturnsNull()
) untuk membuatnya diketikboolean
. Ini tentu saja menyebabkan NPE dari yangnull
dikembalikan pada saat run-time.Untuk E2, jenis operan ke-2 dan ke-3
<special null type>
(tidakBoolean
seperti pada E1!) Danboolean
masing - masing, jadi tidak ada klausa pengetikan spesifik yang berlaku ( baca 'em! ), Jadi klausa "sebaliknya" yang berlaku berlaku:<special null type>
(lihat §4.1 )boolean
<special null type>
(lihat item terakhir dalam daftar konversi tinju di §5.1.7 )Boolean
Jadi jenis ekspresi kondisional adalah
Boolean
dan operan ke-3 harus dipaksaBoolean
. Kompiler memasukkan kode tinju otomatis untuk operan ke-3 (false
). Operan ke-2 tidak memerlukan auto-unboxing seperti padaE1
, jadi tidak ada NPE auto-unboxing ketikanull
dikembalikan.Pertanyaan ini membutuhkan analisis jenis yang serupa:
Operator kondisional Java?: Jenis hasil
sumber
lub
dalamlub(T1,T2)
singkatan?Garis:
diubah secara internal menjadi:
untuk melakukan unboxing; jadi:
null.booleanValue()
akan menghasilkan NPEIni adalah salah satu jebakan utama saat menggunakan autoboxing. Perilaku ini memang didokumentasikan dalam 5.1.8 JLS
Sunting: Saya percaya bahwa unboxing adalah karena operator ketiga adalah tipe boolean, seperti (pemeran implisit ditambahkan):
sumber
Dari Spesifikasi Bahasa Jawa, bagian 15.25 :
Jadi, yang pertama contoh mencoba untuk memanggil
Boolean.booleanValue()
untuk mengkonversiBoolean
keboolean
sesuai aturan pertama.Dalam kasus kedua operan pertama adalah dari jenis nol, ketika yang kedua bukan dari jenis referensi, jadi konversi autoboxing diterapkan:
sumber
null
.boolean
bukan tipe referensi.Kita dapat melihat masalah ini dari kode byte. Pada baris 3 kode byte utama
3: invokevirtual #3 // Method java/lang/Boolean.booleanValue:()Z
,, Boolean nilai nol,invokevirtual
metodejava.lang.Boolean.booleanValue
, itu akan melempar NPE tentu saja.sumber