Pertanyaan 1:
Mengapa kode berikut dikompilasi tanpa memiliki pernyataan pengembalian?
public int a() {
while(true);
}
Perhatikan: Jika saya menambahkan kembali setelah beberapa saat maka saya mendapatkan Unreachable Code Error
.
Pertanyaan 2:
Di sisi lain, mengapa kode berikut dikompilasi,
public int a() {
while(0 == 0);
}
meskipun berikut ini tidak.
public int a(int b) {
while(b == b);
}
java
syntax
while-loop
compilation
return
Willi Mentzel
sumber
sumber
Jawaban:
Ini dicakup oleh JLS§8.4.7 :
Karena kompiler tahu bahwa loop tidak akan pernah berhenti (
true
selalu benar, tentu saja), ia tahu fungsi tidak dapat "kembali secara normal" (jatuhkan ujung tubuhnya), dan dengan demikian tidak apa-apa bahwa tidak adareturn
.Dalam
0 == 0
kasus ini, kompiler tahu bahwa loop tidak akan pernah berhenti (itu0 == 0
akan selalu benar). Tapi untuk itu tidak tahub == b
.Kenapa tidak?
Kompiler memahami ekspresi konstan (§15.28) . Mengutip §15.2 - Bentuk Ekspresi (karena anehnya kalimat ini tidak ada di §15.28) :
Dalam
b == b
contoh Anda , karena ada variabel yang terlibat, itu bukan ekspresi konstan dan tidak ditentukan untuk ditentukan pada waktu kompilasi. Kita bisa melihat bahwa itu selalu akan menjadi benar dalam kasus ini (meskipun jikab
adalahdouble
, sebagai QBrute menunjukkan , kita dapat dengan mudah tertipu olehDouble.NaN
, yang tidak==
sendiri ), tapi JLS hanya menetapkan bahwa ekspresi konstan ditentukan pada waktu kompilasi , itu tidak memungkinkan kompiler untuk mencoba mengevaluasi ekspresi yang tidak konstan. bayou.io mengemukakan suatu alasan mengapa tidak: Jika Anda mulai mencoba menentukan ekspresi yang melibatkan variabel pada waktu kompilasi, di mana Anda berhenti?b == b
jelas (eh, untuk non-NaN
nilai), tetapi bagaimana dengana + b == b + a
? Atau(a + b) * 2 == a * 2 + b * 2
? Menggambar garis pada konstanta masuk akal.Jadi karena ia tidak "menentukan" ekspresi, kompiler tidak tahu bahwa loop tidak akan pernah berhenti, jadi ia berpikir metode tersebut dapat kembali secara normal - yang tidak diperbolehkan untuk dilakukan, karena itu diperlukan untuk digunakan
return
. Jadi itu mengeluh tentang kurangnya areturn
.sumber
Mungkin menarik untuk memikirkan jenis metode pengembalian bukan sebagai janji untuk mengembalikan nilai dari jenis yang ditentukan, tetapi sebagai janji untuk tidak mengembalikan nilai yang bukan dari jenis yang ditentukan. Jadi, jika Anda tidak pernah mengembalikan apa pun, Anda tidak melanggar janji, dan salah satu dari berikut ini sah:
Looping selamanya:
Berulang selamanya:
Membuang pengecualian:
(Saya menemukan rekursi yang menyenangkan untuk dipikirkan: Kompilator percaya bahwa metode ini akan mengembalikan nilai tipe
X
(apa pun itu), tetapi itu tidak benar, karena tidak ada kode yang memiliki ide bagaimana membuat atau pengadaanX
.)sumber
Melihat kode byte, jika apa yang dikembalikan tidak sesuai dengan definisi, Anda akan menerima kesalahan kompilasi.
Contoh:
for(;;)
akan menampilkan bytecodes:Perhatikan kurangnya bytecode pengembalian
Ini tidak pernah mencapai pengembalian, dan dengan demikian tidak mengembalikan jenis yang salah.
Sebagai perbandingan, metode seperti:
Akan mengembalikan bytecode berikut:
Perhatikan "areturn" yang berarti "kembalikan referensi"
Sekarang jika kita melakukan hal berikut:
Akan mengembalikan bytecode berikut:
Sekarang kita dapat melihat bahwa tipe dalam definisi tidak cocok dengan tipe pengembalian ireturn, yang berarti return int.
Jadi sebenarnya apa yang turun adalah bahwa jika metode ini memiliki jalur kembali, jalur itu harus cocok dengan tipe pengembalian. Tetapi ada beberapa contoh dalam bytecode di mana tidak ada jalan kembali yang dihasilkan sama sekali, dan dengan demikian tidak ada pelanggaran aturan.
sumber