Ruby異常捕獲
當Ruby的代碼運行異常時,會拋出異常,我們在開發(fā)時隨時可能會發(fā)生異常,本章節(jié)中讓我們來了解Ruby中的異常。
1. 什么是異常
在 Ruby 中異常是一種特殊的對象,它是 Exception 實例或這個類的子類。下面引用《Programming Ruby》書中的一個圖片。
默認情況下,當程序發(fā)生異常,Ruby程序會立即終止。不過我們可以使用異常處理機制來處理程序中遇到的異常,它是一個代碼塊,當異常發(fā)生時,將執(zhí)行異常處理的代碼。
2. raise拋出異常
除了編程異常出現(xiàn)的異常外,我們可以使用raise
來強制拋出一個異常。
實例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
raise_exception
# ---- 輸出結果 ----
before raise exception
Traceback (most recent call last):
1: from test.rb:7:in `<main>'
test.rb:3:in `raise_exception': This is a exception (RuntimeError)
解釋:由打印我們可以看到,當執(zhí)行完"before raise exception"的文字輸出后,程序拋出了一個異常,這個異常的名稱是我們定義的“This is a exception”。
Tips:默認情況下,raise創(chuàng)建RuntimeError類的異常。
我們也可以通過傳入異常的類型,來改變raise異常的類型。
實例:
def inverse(x)
raise ArgumentError, 'Argument is not numeric' unless x.is_a? Numeric
1.0 / x
end
puts inverse(2)
puts inverse('not a number')
# ---- 輸出結果 ----
0.5
Traceback (most recent call last):
1: from test.rb:6:in `<main>'
test.rb:2:in `inverse': Argument is not numeric (ArgumentError)
解釋: 我們在raise
后面增加了需要拋出的異常類型,由輸出結果我們可以看到,最后拋出的異常類型為ArgumentError。
3. 異常處理
為了捕獲異常處理,我們使用begin-end
將可能發(fā)生異常的代碼封裝它之中,并使用rescue
告訴我們要處理異常的類型。
讓我們捕獲一下第一個例子的異常。
實例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
begin
raise_exception
rescue Security => e
puts "get the exception"
end
# ---- 輸出結果 ----
before raise exception
get the exception
解釋:由上面例子我們可以看到,當出現(xiàn)異常時,將立刻執(zhí)行rescue
后面的語句,而異常中斷后面的代碼不會執(zhí)行。
Tips:如圖顯示大多數(shù)異常屬于 StandardError,默認情況下,Ruby 的異常捕獲只捕獲StandardError 的異常。
我們也可以將異常對象映射到rescue
的后面來只獲取指定類型的異常。
實例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
begin
raise_exception
rescue SecurityError => e
puts "get the exception"
end
# ---- 輸出結果 ----
before raise exception
Traceback (most recent call last):
1: from test.rb:8:in `<main>'
test.rb:3:in `raise_exception': This is a exception (RuntimeError)
解釋:由于異常的類型是 StandardError,所以并不會觸發(fā)異常捕獲。
我們也可以對多種異常類型進行捕獲。它的形式如下顯示,當異常類型不匹配時,會依次向下進行匹配,如果不發(fā)生異常,將執(zhí)行else
下面的語句。
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# No exceptions
end
實例:
def raise_exception
puts "before raise exception"
raise "This is a exception"
puts "after raise exception"
end
begin
raise_exception
rescue SecurityError => e
puts "get the SecurityError"
rescue StandardError => e
puts "get the StandardError"
end
# ---- 輸出結果 ----
before raise exception
get the StandardError
解釋:當拋出異常后,首先將異常類型和 SecurityError 進行對比,發(fā)現(xiàn)不符合繼續(xù)查找下一個,第二個異常類型 StandardError 和當前異常相符合,于是執(zhí)行了它下面的語句。
4. retry
在捕獲到異常并執(zhí)行rescue
下的語句時,我們還可以使用retry
來重新執(zhí)行發(fā)生異常的代碼。
num = 0
begin
puts "current num = #{num}"
raise if num < 3
puts "finished!"
rescue
num += 1
puts 'retry!'
retry
end
# ---- 輸出結果 ----
current num = 0
retry!
current num = 1
retry!
current num = 2
retry!
current num = 3
finished!
解釋:當num
小于 3 時代碼運行會一直觸發(fā)異常,每次當異常發(fā)生時,執(zhí)行num
的累加操作并執(zhí)行retry,直到 num
等于 3 不拋出異常代碼結束。
5. 小結
本章節(jié)我們學習了什么是異常,使用raise
強制拋出異常,使用begin-end
+rescue
來捕獲異常,以及使用retry
重新運行出現(xiàn)異常的代碼。