1. 程式人生 > Ruby 程式語言入門 >22 Ruby 異常捕獲

22 Ruby 異常捕獲

當Ruby的程式碼執行異常時,會丟擲異常,我們在開發時隨時可能會發生異常,本章節中讓我們來了解Ruby中的異常。

1. 什麼是異常

在 Ruby 中異常是一種特殊的物件,它是 Exception 例項或這個類的子類。下面引用《Programming Ruby》書中的一個圖片。

圖片描述

預設情況下,當程式發生異常,Ruby程式會立即終止。不過我們可以使用異常處理機制來處理程式中遇到的異常,它是一個程式碼塊,當異常發生時,將執行異常處理的程式碼。

2. raise丟擲異常

除了程式設計異常出現的異常外,我們可以使用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)

解釋:由列印我們可以看到,當執行完"before raise exception"的文字輸出後,程式丟擲了一個異常,這個異常的名稱是我們定義的“This is a exception”。

Tips:預設情況下,raise建立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將可能發生異常的程式碼封裝它之中,並使用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

解釋:由上面例子我們可以看到,當出現異常時,將立刻執行rescue後面的語句,而異常中斷後面的程式碼不會執行。

Tips:如圖顯示大多數異常屬於 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,所以並不會觸發異常捕獲。

我們也可以對多種異常型別進行捕獲。它的形式如下顯示,當異常型別不匹配時,會依次向下進行匹配,如果不發生異常,將執行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 進行對比,發現不符合繼續查詢下一個,第二個異常型別 StandardError 和當前異常相符合,於是執行了它下面的語句。

4. retry

在捕獲到異常並執行rescue下的語句時,我們還可以使用retry來重新執行發生異常的程式碼。

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 時程式碼執行會一直觸發異常,每次當異常發生時,執行num的累加操作並執行retry,直到 num 等於 3 不丟擲異常程式碼結束。

5. 小結

本章節我們學習了什麼是異常,使用raise強制丟擲異常,使用begin-end+rescue來捕獲異常,以及使用retry重新執行出現異常的程式碼。