Tanpa Pengecualian saat mengetikkan casting dengan null di java

227
String x = (String) null;

Mengapa tidak ada pengecualian dalam pernyataan ini?

String x = null;
System.out.println(x);

Mencetak null. Tetapi .toString()metode harus membuang pengecualian pointer nol.

Vicky
sumber
pengecualian apa yang Anda bicarakan, kompiler?
Sajan Chandran

Jawaban:

323

Anda dapat menggunakan nulltipe referensi apa pun tanpa mendapatkan pengecualian.

The printlnmetode tidak membuang nol pointer karena cek dulu apakah objek tersebut adalah null atau tidak. Jika null maka itu hanya mencetak string "null". Kalau tidak, ia akan memanggil toStringmetode objek itu.

Menambahkan rincian lebih lanjut: Metode pencetakan metode panggilan internal String.valueOf(object)pada objek input. Dan dalam valueOfmetode, pemeriksaan ini membantu menghindari pengecualian null pointer:

return (obj == null) ? "null" : obj.toString();

Untuk sisa kebingungan Anda, memanggil metode apa pun pada objek nol harus membuang pengecualian pointer nol, jika bukan kasus khusus.

Juned Ahsan
sumber
1
@JunedAhsan kasus khusus apa yang menyebabkannya tidak melempar NPE?
Holloway
@ Trengot Periksa satu yang disebutkan dalam jawaban Peter di bawah ini.
Juned Ahsan
144

Anda dapat menggunakan nulltipe referensi apa pun. Anda juga dapat memanggil metode yang menangani nullsebagai argumen, misalnya System.out.println(Object), tetapi Anda tidak bisa mereferensikan nullnilai dan memanggil metode.

BTW Ada situasi sulit di mana Anda bisa memanggil metode statis pada nullnilai.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.
Peter Lawrey
sumber
12
Wow. Jika ditanya, saya akan 100% yakin bahwa itu akan menimbulkan pengecualian. Kasus yang rumit memang.
Magnilex
2
@Magnilex: Benar-benar! ini adalah pertanyaan tipuan ujian OCPJP yang khas.
ccpizza
3
Bukankah ini karena kompiler dalam bytecode "mengoptimalkan" itu t.yield() -> Thread.yeld() ? Mirip dengan bagaimana final int i = 1; while (i == 1)dioptimalkan untukwhile(true)
SGal
@ SGAL Ini lebih baik karena optimasi kedua adalah AFAIK tidak wajib sedangkan yang pertama agak adalah.
Paul Stelian
36

Ini dengan desain. Anda dapat menggunakan nulltipe referensi apa pun. Kalau tidak, Anda tidak akan dapat menetapkannya ke variabel referensi.

André Stannek
sumber
Terima kasih! catatan tentang variabel nol untuk referensi ini sangat membantu!
Maks
22

Casting nilai null diperlukan untuk mengikuti konstruksi di mana metode kelebihan beban dan jika nol dilewatkan ke metode kelebihan beban ini maka kompiler tidak tahu cara menghapus ambiguitas maka kita perlu mengetikkan nol dalam kasus ini:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

Kalau tidak, Anda tidak dapat memanggil metode yang Anda butuhkan.

Mewel
sumber
Dalam kebanyakan kasus casting adalah implisit, misalnya String bar = null;melemparkan nullnilai ke String. Sejauh ini saya hanya perlu memberikan null secara eksplisit dalam tes di mana metode kelebihan beban dan saya ingin menguji perilakunya dengan input nol. Namun, baik untuk mengetahui, saya akan menulis jawaban yang sama sebelum saya menemukan jawaban Anda.
Vlasec
Fakta menyenangkan: l instanceof Longdan s instanceof Stringakan kembali falsedalam kasus ini.
Attila Tanyi
7

Println(Object) menggunakan String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) tidak memeriksa nol.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}
rocketboy
sumber
5

Banyak jawaban di sini sudah disebutkan

Anda dapat menggunakan nol untuk semua jenis referensi

dan

Jika argumennya nol, maka sebuah string sama dengan "null"

Saya bertanya-tanya di mana itu ditentukan dan mencarinya di Spesifikasi Java:

Referensi nol selalu dapat ditetapkan atau dilemparkan ke jenis referensi apa pun (§5.2, §5.3, §5.5).

Jika referensi adalah nol, itu dikonversi ke string "null" (empat karakter ASCII n, u, l, l).

Arigion
sumber
3

Seperti yang ditulis orang lain, Anda dapat membatalkan semua hal. Biasanya, Anda tidak membutuhkan itu, Anda dapat menulis:

String nullString = null;

tanpa meletakkan gips di sana.

Tetapi ada saat-saat di mana pemain seperti itu masuk akal:

a) jika Anda ingin memastikan bahwa metode tertentu dipanggil, seperti:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

maka itu akan membuat perbedaan jika Anda mengetik

foo((String) null) vs. foo(null)

b) jika Anda bermaksud menggunakan IDE untuk menghasilkan kode; misalnya saya biasanya menulis tes unit seperti:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Saya sedang melakukan TDD; ini berarti bahwa kelas "MyClassUnderTest" mungkin belum ada. Dengan menuliskan kode itu, saya kemudian dapat menggunakan IDE saya untuk pertama-tama menghasilkan kelas baru; dan kemudian menghasilkan konstruktor yang menerima argumen "Apa pun" "di luar kotak" - IDE dapat memperkirakan dari pengujian saya bahwa konstruktor harus mengambil tepat satu argumen dari tipe Apa pun.

GhostCat
sumber
2

Cetak :

Cetak objek. String yang dihasilkan oleh metode String.valueOf (Object) diterjemahkan ke dalam byte

Nilai dari :

jika argumennya nol, maka sebuah string sama dengan "null"; jika tidak, nilai obj.toString () dikembalikan.

Itu hanya akan mengembalikan string dengan nilai "null" ketika objek tersebut null.

Jeroen Vannevel
sumber
2

Ini sangat berguna ketika menggunakan metode yang seharusnya tidak jelas. Sebagai contoh: JDialog memiliki konstruktor dengan tanda tangan berikut:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

Saya perlu menggunakan konstruktor ini, karena saya ingin mengatur GraphicsConfiguration, tetapi saya tidak memiliki orang tua untuk dialog ini, jadi argumen pertama harus nol. Menggunakan

JDialog(null, String, boolean, Graphicsconfiguration) 

ambigu, jadi dalam hal ini saya dapat mempersempit panggilan dengan memberikan null ke salah satu jenis yang didukung:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)
Marten Jacobs
sumber
0

Fitur bahasa ini nyaman dalam situasi ini.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Jika memberHashMap.get ("Name") mengembalikan null, Anda tetap menginginkan metode di atas mengembalikan null tanpa melempar pengecualian. Tidak peduli apa kelasnya, nol adalah nol.

Lagu Changgull
sumber