Ini akan menjadi jawaban konseptual mengapa peringatan ini mungkin ada bahkan dengan pendekatan coba-dengan-sumber daya. Sayangnya, ini juga bukan solusi mudah yang mungkin Anda harapkan untuk dicapai.
Pemulihan Kesalahan Tidak Dapat Gagal
finally
model aliran kontrol pasca transaksi yang dieksekusi terlepas dari apakah transaksi berhasil atau gagal.
Dalam kasus gagal, finally
tangkap logika yang dijalankan di tengah pemulihan dari kesalahan, sebelum dipulihkan sepenuhnya (sebelum kami mencapai catch
tujuan kami ).
Bayangkan masalah konseptual yang dihadirkannya untuk menemui kesalahan di tengah pemulihan dari kesalahan.
Bayangkan sebuah server basis data tempat kami mencoba melakukan transaksi, dan gagal setengah jalan (misalnya server kehabisan memori di tengah). Sekarang server ingin memutar kembali transaksi ke titik seolah-olah tidak ada yang terjadi. Namun bayangkan itu menemukan kesalahan lain dalam proses mundur. Sekarang kita memiliki transaksi setengah berkomitmen pada basis data - atomisitas dan sifat transaksi yang tidak dapat dibagi sekarang rusak, dan integritas basis data sekarang akan dikompromikan.
Masalah konseptual ini ada dalam bahasa apa pun yang berurusan dengan kesalahan apakah itu C dengan propagasi kode kesalahan manual, atau C ++ dengan pengecualian dan destruktor, atau Java dengan pengecualian dan finally
.
finally
tidak dapat gagal dalam bahasa yang menyediakannya dengan cara yang sama destruktor tidak bisa gagal dalam C ++ dalam proses menemukan pengecualian.
Satu-satunya cara untuk menghindari masalah konseptual dan sulit ini adalah untuk memastikan bahwa proses memutar kembali transaksi dan melepaskan sumber daya di tengah tidak mungkin menemukan pengecualian / kesalahan rekursif.
Jadi satu-satunya desain yang aman di sini adalah desain yang writer.close()
tidak mungkin gagal. Biasanya ada cara-cara dalam desain untuk menghindari skenario di mana hal-hal seperti itu bisa gagal di tengah-tengah pemulihan, membuatnya mustahil.
Sayangnya itu satu-satunya cara - pemulihan kesalahan tidak bisa gagal. Cara termudah untuk memastikan ini adalah membuat fungsi "pelepasan sumber daya" dan "efek samping terbalik" semacam itu tidak mampu gagal. Itu tidak mudah - pemulihan kesalahan yang tepat sulit dan juga sayangnya sulit untuk diuji. Tetapi cara untuk mencapainya adalah memastikan bahwa setiap fungsi yang "menghancurkan", "menutup", "mematikan", "memutar kembali", dll. Tidak mungkin mengalami kesalahan eksternal dalam proses, karena fungsi seperti itu sering perlu dipanggil di tengah memulihkan dari kesalahan yang ada.
Contoh: Logging
Katakanlah Anda ingin mencatat barang di dalam finally
blok. Ini sering menjadi masalah besar kecuali penebangan tidak bisa gagal . Penebangan hampir pasti dapat gagal, karena mungkin ingin menambahkan lebih banyak data ke file, dan itu dapat dengan mudah menemukan banyak alasan untuk gagal.
Jadi solusinya di sini adalah membuatnya sehingga fungsi logging apa pun yang digunakan dalam finally
blok tidak bisa melempar ke pemanggil (mungkin bisa gagal, tetapi tidak mau membuang). Bagaimana mungkin kita melakukan itu? Jika bahasa Anda memungkinkan melempar dalam konteks yang akhirnya asalkan ada blok coba / tangkap bersarang, itu akan menjadi salah satu cara untuk menghindari melempar ke pemanggil dengan menelan pengecualian dan mengubahnya menjadi kode kesalahan, mis. Mungkin penebangan dapat dilakukan secara terpisah proses atau utas yang dapat gagal secara terpisah dan di luar tumpukan pemulihan kesalahan pemulihan yang ada. Selama Anda dapat berkomunikasi dengan proses itu tanpa kemungkinan mengalami kesalahan, itu juga akan menjadi pengecualian-aman, karena masalah keselamatan hanya ada dalam skenario ini jika kita melempar secara rekursif dari dalam utas yang sama.
Dalam hal ini, kita bisa lolos dari kegagalan penebangan asalkan tidak membuang karena gagal login dan tidak melakukan apa-apa bukanlah akhir dunia (itu tidak membocorkan sumber daya apa pun atau gagal memutar kembali efek samping, misalnya).
Lagi pula, saya yakin Anda sudah bisa mulai membayangkan betapa sulitnya untuk benar-benar membuat perangkat lunak menjadi pengecualian. Mungkin tidak perlu mencari ini pada tingkat tertinggi di semua kecuali perangkat lunak yang paling penting. Tetapi perlu dicatat bagaimana cara benar-benar mencapai keamanan pengecualian, karena bahkan penulis perpustakaan yang sangat umum sekalipun sering gagal di sini dan menghancurkan seluruh keamanan aplikasi Anda menggunakan perpustakaan.
SomeFileWriter
Jika SomeFileWriter
bisa melempar ke dalam close
, maka saya akan mengatakan itu umumnya tidak kompatibel dengan penanganan pengecualian, kecuali jika Anda tidak pernah mencoba untuk menutupnya dalam konteks yang melibatkan pemulihan dari pengecualian yang ada. Jika kode untuk itu berada di luar kendali Anda, kami mungkin SOL tetapi layak memberi tahu penulis tentang masalah keselamatan pengecualian yang mencolok ini. Jika itu dalam kendali Anda, rekomendasi utama saya adalah memastikan bahwa menutupnya tidak mungkin gagal dengan cara apa pun yang diperlukan.
Bayangkan jika sistem operasi benar-benar gagal untuk menutup file. Sekarang setiap program yang mencoba untuk menutup file saat dimatikan akan gagal ditutup . Apa yang harus kita lakukan sekarang, biarkan aplikasi tetap terbuka dan dalam limbo (mungkin tidak), bocor sumber daya file dan abaikan masalahnya (mungkin baik-baik saja jika tidak terlalu kritis)? Desain teraman: buat jadi tidak mungkin untuk gagal menutup file.