Apa perbedaan antara "raise" foo "` dan `raise Exception.new (" foo ")`?

103

Apa perbedaan - teknis, filosofis, konseptual, atau lainnya - antara

raise "foo"

dan

raise Exception.new("foo")

?

John Bachir
sumber

Jawaban:

121

Secara teknis, yang pertama memunculkan RuntimeError dengan pesan disetel ke "foo", dan yang kedua memunculkan Pengecualian dengan pesan disetel ke "foo".

Secara praktis, ada perbedaan yang signifikan antara kapan Anda ingin menggunakan yang pertama dan kapan Anda ingin menggunakan yang kedua.

Sederhananya, Anda mungkin menginginkan file RuntimeErrorbukan Exception. Blok penyelamatan tanpa argumen akan menangkap RuntimeErrors, tetapi TIDAK akan menangkap Exceptions. Jadi jika Anda meningkatkan Exceptionkode Anda, kode ini tidak akan menangkapnya:

begin
rescue
end

Untuk menangkapnya, ExceptionAnda harus melakukan ini:

begin
rescue Exception
end

Ini berarti bahwa dalam arti tertentu, an Exceptionadalah kesalahan yang "lebih buruk" daripada a RuntimeError, karena Anda harus bekerja lebih keras untuk memulihkannya.

Jadi yang Anda inginkan tergantung pada bagaimana proyek Anda melakukan penanganan kesalahannya. Misalnya, dalam daemon kami, loop utama memiliki penyelamatan kosong yang akan menangkap RuntimeErrors, melaporkannya, dan kemudian melanjutkan. Tetapi dalam satu atau dua keadaan, kami ingin daemon benar-benar mati karena kesalahan, dan dalam hal ini kami memunculkan Exception, yang langsung melewati "kode penanganan kesalahan normal" dan keluar.

Dan lagi, jika Anda menulis kode pustaka, Anda mungkin menginginkan a RuntimeError, bukan an Exception, karena pengguna pustaka Anda akan terkejut jika itu menimbulkan kesalahan yang rescuetidak dapat ditangkap oleh blok kosong , dan itu akan membutuhkan waktu beberapa saat untuk menyadari alasannya.

Akhirnya, saya harus mengatakan bahwa itu RuntimeErroradalah subkelas dari StandardErrorkelas, dan aturan sebenarnya adalah bahwa meskipun Anda dapat raise semua jenis objek, kosong rescuesecara default hanya akan menangkap apa pun yang mewarisi dari StandardError. Segala sesuatu yang lain harus spesifik.

Daniel Lucraft
sumber
2
sangat informatif, terima kasih. beberapa hal: [1] Paragraf terakhir itu adalah yang paling mencerahkan, dan izinkan saya menemukan di irb sesuatu yang tidak Anda sebutkan: RuntimeError < StandardError < Exception[2] oleh karena itu, blok kode kedua itu akan menangkap Exception dan RuntimeError [3] menarik / aneh bahwa kenaikan dan penyelamatan "telanjang" bekerja dengan Exception tertentu [4] mungkin aturan praktisnya adalah menaikkan RuntimeError ke kode klien, tetapi meningkatkan dan menyelamatkan Pengecualian kustomnya sendiri di dalam kodenya sendiri?
John Bachir
1
[1, 2] Ya. [3] tidak yakin ... [4] Saat saya membuat kode paling profesional, saya cenderung membuat jenis kesalahan khusus yang mewarisi StandardError. Tidak harus lebih rumit dari beberapa baris class MissingArgumentsError < StandardError; end.
Daniel Lucraft
Sangat informatif, tetapi dalam situasi seperti apa Anda ingin menampilkan Exception daripada run time error jika run time error lebih disukai untuk menulis libraray?
Chihung Yu
35

Dari dokumentasi resmi:

raise   
raise( string )
raise( exception [, string [, array ] ] )

Tanpa argumen, memunculkan pengecualian $!atau RuntimeErrorjika $!nihil. Dengan satu Stringargumen, ini memunculkan a RuntimeErrordengan string sebagai pesan. Jika tidak, parameter pertama harus nama Exceptionkelas (atau objek yang mengembalikan Exceptionpengecualian saat dikirim). Parameter opsional kedua menyetel pesan yang terkait dengan pengecualian, dan parameter ketiga adalah larik informasi panggilan balik. Pengecualian ditangkap oleh klausul penyelamatan begin...endblok.

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
ennuikiller
sumber