Saya memiliki kelas Java sederhana seperti yang ditunjukkan di bawah ini:
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
Dan output dari kode ini adalah ini:
Entry in finally Block
dev
Mengapa s
tidak diganti dalam finally
blok, belum mengontrol hasil cetak?
java
try-finally
Pengembang
sumber
sumber
s
sebelum Anda mengubah nilainya.finally
blok , tidak seperti di C # (yang tidak dapat Anda)Jawaban:
The
try
blok Rampungkan dengan pelaksanaanreturn
pernyataan dan nilais
pada saatreturn
pernyataan mengeksekusi adalah nilai yang dikembalikan oleh metode ini. Fakta bahwafinally
klausa kemudian mengubah nilais
(setelahreturn
pernyataan selesai) tidak (pada saat itu) mengubah nilai kembali.Perhatikan bahwa di atas berkaitan dengan perubahan nilai
s
itu sendiri difinally
blok, bukan ke objek yangs
direferensikan. Jikas
referensi ke objek yang bisa berubah (yangString
tidak) dan isi objek diubah difinally
blok, maka perubahan itu akan terlihat pada nilai yang dikembalikan.Aturan terperinci untuk bagaimana semua ini beroperasi dapat ditemukan di Bagian 14.20.2 dari Spesifikasi Bahasa Jawa . Perhatikan bahwa eksekusi
return
pernyataan diperhitungkan sebagai penghentian mendadaktry
blok (bagian mulai " Jika eksekusi blok coba selesai tiba-tiba karena alasan lain R .... " berlaku). Lihat Bagian 14.17 dari JLS untuk alasan mengapa suatureturn
pernyataan tiba-tiba merupakan penghentian blok.Dengan perincian lebih lanjut: jika
try
blok danfinally
bloktry-finally
pernyataan berakhir tiba-tiba karenareturn
pernyataan, maka aturan berikut dari §14.20.2 berlaku:Hasilnya adalah bahwa
return
pernyataan difinally
blok menentukan nilai kembali seluruhtry-finally
pernyataan, dan nilai yang dikembalikan daritry
blok dibuang. Hal serupa terjadi dalamtry-catch-finally
pernyataan jikatry
blok melempar pengecualian, ditangkap olehcatch
blok, dan baikcatch
blok maupunfinally
blok memilikireturn
pernyataan.sumber
finally
blok tidak mengubah objek yang dikembalikan (yangStringBuilder
) tetapi dapat mengubah internal objek. Thefinally
mengeksekusi blok sebelum metode benar-benar kembali (meskipunreturn
pernyataan telah selesai), sehingga perubahan itu terjadi sebelum kode memanggil melihat nilai yang dikembalikan.StringBuilder
,List
,Set
, iklan nauseum): jika Anda mengubah isi dalamfinally
blok, maka perubahan tersebut terlihat pada kode panggilan ketika metode akhirnya keluar.Karena nilai balik diletakkan di tumpukan sebelum panggilan ke akhirnya.
sumber
=
tidak akan bermutasi.finally
blok OP tidak mempengaruhi nilai kembali. Saya pikir apa yang templatetypedef mungkin dapatkan (meskipun ini tidak jelas) adalah bahwa karena nilai yang dikembalikan adalah referensi ke objek yang tidak dapat diubah, bahkan mengubah kode difinally
blok (selain menggunakanreturn
pernyataan lain ) tidak dapat mempengaruhi nilai yang dikembalikan dari metode.Jika kita melihat ke dalam bytecode, kita akan melihat bahwa JDK telah membuat optimasi yang signifikan, dan metode foo () terlihat seperti:
Dan bytecode:
java mempertahankan string "dev" agar tidak diubah sebelum kembali. Bahkan di sini akhirnya tidak ada blok sama sekali.
sumber
Ada 2 hal yang patut diperhatikan di sini:
sumber
finally
klausa, itu akan terlihat dalam kode panggilan. Namun, jika Anda menetapkan stringbuffer barus
, maka perilakunya akan sama seperti sekarang.Saya sedikit mengubah kode Anda untuk membuktikan maksud Ted.
Seperti yang Anda lihat di output
s
memang berubah tetapi setelah pengembalian.Keluaran:
sumber
Secara teknis,
return
blok uji coba tidak akan diabaikan jikafinally
blok ditentukan, hanya jika blok akhirnya juga menyertakan areturn
.Ini adalah keputusan desain yang meragukan yang mungkin merupakan kesalahan dalam retrospeksi (seperti referensi yang dapat dibatalkan / dapat diubah secara default, dan, menurut beberapa, mengecek pengecualian). Dalam banyak hal perilaku ini persis konsisten dengan pemahaman sehari-hari tentang apa
finally
artinya - "tidak peduli apa yang terjadi sebelumnya ditry
blok, selalu jalankan kode ini." Karenanya, jika Anda mengembalikan true darifinally
blok, efek keseluruhan harus selalu kereturn s
, bukan?Secara umum, ini jarang idiom yang baik, dan Anda harus menggunakan
finally
blok secara bebas untuk membersihkan / menutup sumber daya tetapi jarang jika pernah mengembalikan nilai dari mereka.sumber
Coba ini: Jika Anda ingin mencetak nilai ganti s.
sumber