Perilaku ternary Java yang aneh saat menetapkan nilai. Apa yang dilakukan Java di balik layar agar ini terjadi?

10

Beberapa hari yang lalu, saya mengalami skenario yang menarik bahwa saya tidak dapat menemukan dokumentasi tentang bagaimana atau mengapa Java memungkinkan hal berikut terjadi. (Cuplikan ini hanyalah bentuk bug yang disederhanakan.)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

dalam cuplikan di atas:

jika bool = true, maka Anda mendapatkan nilai '5';

tetapi jika bool = false, maka Anda mendapatkan pengecualian pointer nol ketika mencoba mengevaluasi operasi ternary. BUKAN pernyataan cetak.


Untuk memperbaiki ini saya hanya mengubah 'hasil' menjadi

Long result = bool ? Long.valueOf(intVal) : longVal;

Melakukan ini, akan memberikan perilaku yang diharapkan yang saya butuhkan:

jika bool = true, maka Anda mendapatkan nilai '5';

tetapi jika bool = false, maka Anda mendapatkan 'null'


sekarang bagian yang menyenangkan adalah jika Anda membaginya menjadi pernyataan if / else normal, maka java TIDAK membiarkan Anda mengkompilasi

longVal = intVal; 

tetapi tidak menangkapnya melalui operator ternary. Jadi apa yang dilakukan Java untuk menjadikannya titik nol di cuplikan asli?

(java 11)

Tim Z.
sumber

Jawaban:

10

Ketika Anda melakukan ini:

Long result = bool ? intVal : longVal

Ekspresi ini mengembalikan a longdan, ketika boolfalse ia mencoba untuk unboxe nullke nilai Long agar sesuai dengan resultvariabel dan melempar NPE.

Ketika Anda melakukan ini:

Long result = bool ? Long.valueOf(intVal) : longVal

Ekspresi ini sudah kembali Longmaka tidak perlu untuk unboxing dan nullnilai berhasil ditetapkan ke resultvariabel.

Referensi:

Sebagaimana dibahas di bagian komentar, untuk lebih memahami mengapa ini terjadi, periksa bagian JLS berikut:

Diego Magdaleno
sumber
Saya terkejut Anda tabel referensi yang berbeda 15.25 A ke E di mana "jelas" bahwa Integer / Long menghasilkan bnp (Integer, Long).
matt
Jawaban yang bagus. Secara umum ketika saya benar-benar tidak tahu, apa yang terjadi di dalam, saya sarankan melihat-lihat di bytecode yang dikompilasi, yang mengungkapkan hampir persis, apa yang dijelaskan. Setidaknya ketika mengekstraksi potongan kode minimal, itu kurang lebih soal pelatihan, cara membaca dan memahaminya.
Jan Diadakan
Seperti yang dikatakan JLS, Bagian 5.6.2 : "Jika ada operan dari tipe referensi, itu akan dikenakan konversi unboxing"; kemudian "Pelebaran konversi primitif (§5.1.2) diterapkan [..]"
Diego Magdaleno