Jaka jest różnica między `raise" foo "` i `raise Exception.new (" foo ")`?

103

Jaka jest różnica - techniczna, filozoficzna, konceptualna lub inna - między

raise "foo"

i

raise Exception.new("foo")

?

John Bachir
źródło

Odpowiedzi:

121

Technicznie rzecz biorąc, pierwszy wywołuje RuntimeError z komunikatem ustawionym na "foo", a drugi zgłasza wyjątek z komunikatem ustawionym na "foo".

Praktycznie istnieje znacząca różnica między tym, kiedy chcesz użyć pierwszego, a kiedy chcesz użyć drugiego.

Mówiąc najprościej, prawdopodobnie chcesz mieć RuntimeErrornie Exception. Blok ratunkowy bez argumentu złapie RuntimeErrors, ale NIE złapie Exceptions. Więc jeśli podniesiesz an Exceptionw swoim kodzie, ten kod go nie złapie:

begin
rescue
end

Aby go złapać Exception, musisz to zrobić:

begin
rescue Exception
end

Oznacza to, że w pewnym sensie an Exceptionjest „gorszym” błędem niż a RuntimeError, ponieważ musisz wykonać więcej pracy, aby się z niego wyleczyć.

Więc to, co chcesz, zależy od tego, jak twój projekt obsługuje obsługę błędów. Na przykład w naszych demonach główna pętla ma pusty ratunek, który złapie RuntimeErrors, zgłosi je, a następnie będzie kontynuował. Ale w jednej lub dwóch okolicznościach chcemy, aby demon naprawdę umarł z powodu błędu, iw takim przypadku wywołujemy an Exception, który przechodzi prosto przez nasz „normalny kod obsługi błędów” i wychodzi.

I znowu, jeśli piszesz kod biblioteki, prawdopodobnie chcesz a RuntimeError, a nie an Exception, ponieważ użytkownicy Twojej biblioteki będą zaskoczeni, jeśli spowoduje to pojawienie się błędów, których pusty rescueblok nie może przechwycić, i zajmie im chwilę, zanim zrozumieją, dlaczego.

Na koniec powinienem powiedzieć, że RuntimeErrorjest podklasą tej StandardErrorklasy, a aktualna zasada jest taka, że ​​chociaż można obiektami raise dowolnego typu, puste pole rescuedomyślnie przechwytuje tylko wszystko, co dziedziczy StandardError. Wszystko inne musi być konkretne.

Daniel Lucraft
źródło
2
bardzo pouczające, dzięki. kilka rzeczy: [1] Ten ostatni akapit był najbardziej pouczające i pozwól mi odkryć w IRB coś, czego nie wzmianka: RuntimeError < StandardError < Exception[2], w związku z tym, że drugi blok kodu będzie złapać zarówno wyjątek a RuntimeError [3] to ciekawe / dziwne, że „nagie” podniesienie i uratowanie działa z tym konkretnym Wyjątkiem [4]. Być może ogólną zasadą jest podniesienie RuntimeError do kodu klienta, ale podniesienie i uratowanie własnych niestandardowych wyjątków wewnątrz własnego kodu?
John Bachir
1
[1, 2] Tak. [3] nie jestem pewien ... [4] Kiedy programuję najbardziej profesjonalnie, zazwyczaj tworzę niestandardowe typy błędów, które dziedziczą po StandardError. Nie musi to być bardziej skomplikowane niż kilka linijek class MissingArgumentsError < StandardError; end.
Daniel Lucraft
Bardzo pouczające, ale w jakich sytuacjach będziesz chciał zgłosić wyjątek, a nie błąd czasu wykonania, jeśli błąd czasu wykonania jest preferowany do pisania libraray?
Chihung Yu
35

Z oficjalnej dokumentacji:

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

Bez argumentów zgłasza wyjątek $!lub podnosi RuntimeErrorjeśli $!jest równe zero. Za pomocą pojedynczego Stringargumentu podnosi RuntimeErrorciąg znaków jako komunikat. W przeciwnym razie pierwszym parametrem powinna być nazwa Exceptionklasy (lub obiekt, który zwraca Exceptionwyjątek po wysłaniu). Opcjonalny drugi parametr ustawia komunikat skojarzony z wyjątkiem, a trzeci parametr jest tablicą informacji zwrotnych. Wyjątki są objęte klauzulą ​​ratunkową begin...endbloków.

raise "Failed to create socket"
raise ArgumentError, "No parameters", caller
ennuikiller
źródło