Ruby異常是一個物件,該類的異常或後代的範例。它代表一些特殊的條件。
在Ruby程式出現錯誤時,會引發異常行為。 預設情況下,Ruby程式在丟擲異常時終止。
我們可以在Ruby中宣告一些例外處理程式。 例外處理程式是一些程式碼塊,當一些其他程式碼塊發生異常時,該塊被執行。
異常的情況以兩種方式處理。 可以終止程式或處理異常。 如果要處理異常,可以提供一個rescue
子句,這樣程式控制就可以流向rescue
子句。
當異常提出但未處理時,全域性變數$!
包含當前異常,$@
包含當前異常的回溯。
Ruby預定義的類,如Exception
及其子項可以用來處理程式的錯誤。 在Ruby異常層次結構中,大多數子類都擴充套件了ClassError
類。 這些是正常的異常。
異常的內建子類如下:
範例
def raise_exception
puts 'I am before the raise.'
raise 'oops! An error has occured'
puts 'I am after the raise'
end
raise_exception
執行上面程式碼,輸出結果如下 -
F:\worksp\ruby>ruby exception-raise.rb
I am before the raise.
exception-raise.rb:6:in `raise_exception': oops! An error has occured (RuntimeError)
from exception-raise.rb:9:in `<main>'
F:\worksp\ruby>
raise
方法來自核心模組。
為了處理異常,引發異常的程式碼包含在begin-end塊中。 使用rescue子句,我們可以說明我們要處理的異常型別。
範例:
#!/usr/bin/ruby
#file: exception-raise_rescue.rb
def raise_and_rescue
begin
puts 'Before the raise.'
raise 'An error occured.'
puts 'After the raise.'
rescue
puts 'Code rescued.'
end
puts 'After the begin block.'
end
raise_and_rescue
執行上面程式碼,得到以下結果 -
F:\worksp\ruby>ruby exception-raise_rescue.rb
Before the raise.
Code rescued.
After the begin block.
F:\worksp\ruby>
在上面的例子中,中斷的程式碼不能完全執行。 例外處理程式碼在開始結束塊(begin-end
)之後恢復。
如果在rescue
子句中未定義任何引數,則該引數預設為StandardError
。 每個rescue
子句指定多個異常捕獲。 如果raise
沒有使用任何引數,則可能會重新提出異常。
rescue
子句寫在begin/rescue
內,如果不是一個由rescue
子句可處理的異常則將由下一個例外處理。
begin
code..
rescue OneTypeOfException
code..
rescue AnotherTypeOfException
code..
else
# Other exceptions
end
在開始(begin
)塊中,每個具有引發異常的rescue
子句將依次與每個引數進行比較。 當在rescue
子句中指定的錯誤型別和異常名稱相同或是該異常的超類時,則將匹配它。 如果沒有異常,完成了begin
語句的主體則執行else
子句。 如果發生異常,則不會執行else
子句。
異常物件是普通物件。rescue
子句中的變數可以儲存被拯救的異常。
範例:
begin
raise 'an exception'
rescue ZeroDivisionError => e
puts "Exception Class: #{ e.class.name }"
puts "Exception Message: #{ e.message }"
puts "Exception Backtrace: #{ e.backtrace }"
end
Exception
類定義了兩種方法用於返回有關異常的詳細資訊。 message
方法返回一個定義錯誤說明的字串。 backtrace
方法返回一個字串陣列,表示在引發異常的時刻呼叫堆疊。
通常在rescue
子句中,捕獲異常並在begin
塊阻止繼續執行程式碼。 使用retry
語句,捕獲塊程式碼可以在捕獲異常之後還可以從begin
塊處恢復。
語法:
begin
code....
rescue
# capture exceptions
retry # program will run from the begin block
end
範例
#!/usr/bin/ruby
begin
x = Dir.mkdir "alreadyExist"
if x
puts "Directory created"
end
rescue
y = "newDir"
retry
end
上述程式執行如下:
步驟1 - 在begin
塊中,編寫程式碼以建立一個已經存在的目錄。
步驟2 - 這將丟擲一個錯誤。
步驟3 - 在rescue
區,y
被重新分配新值。
步驟4 - retry
語句將轉到begin
塊。
步驟5 - 將建立目錄。
raise
語句用於引發異常。
語法:
raise
或者 -
raise "Error Message"
或者 -
raise ExceptionType, "Error Message"
或者 -
raise ExceptionType, "Error Message" condition
第一個語法,重新引發當前的異常。 它用於例外處理程式,其中異常在傳遞之前被攔截。
第二個語法,建立一個新的RuntimeError
異常。 然後這個異常被引發為呼叫堆疊。
第三個語法,使用第一個引數建立一個異常,然後將關聯訊息設定為第二個引數。
第四個語法,類似第三個的語法。 在這裡可以新增任何條件語句來引發異常。
範例
#!/usr/bin/ruby
# exceptions-raise-statement.rb
begin
puts 'code before raise.'
raise 'exception occurred.'
puts 'code after raise.'
rescue
puts 'I am rescued.'
end
puts 'code after begin block.'
執行上面程式碼,得到以下結果 -
F:\worksp\ruby>ruby exceptions-raise-statement.rb
code before raise.
I am rescued.
code after begin block.
F:\worksp\ruby>
有一個ensure
子句,保證在程式碼結尾處的一些處理。無論是否引發異常 ensure
塊始終執行。 它放置在最後一個rescue
子句之後,並且在塊的結束時執行。
無論是否發生異常,異常被rescue
或程式碼被未捕獲的異常終止,ensure
塊都將執行。
語法
begin
code..
#..raise exception
rescue
#.. exception is rescued
ensure
#.. This code will always execute.
end
範例程式碼
#!/usr/bin/ruby
# file : exception-ensure-statment.rb
begin
raise 'Exception'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "The ensure code will always run"
end
執行上面範例程式碼,得到以下結果 -
F:\worksp\ruby>ruby exception-ensure-statment.rb
Exception
["exception-ensure-statment.rb:5:in `<main>'"]
The ensure code will always run
F:\worksp\ruby>
else
子句始終存在於rescue
子句之後和before
子句之前。 如果沒有引發異常,則只執行其他塊。
語法:
begin
code..
#..raise exception
rescue
# .. exception is rescued
else
#.. executes if there is no exception
ensure
#.. This code will always execute.
end
範例
#!/usr/bin/ruby
# file : exception-else-statment.rb
begin
# raise 'A test exception.'
puts "no exception is raised"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "else code will be executed as no exception is raised."
ensure
puts "ensure code will run"
end
執行上面程式碼,得到以下結果 -
F:\worksp\ruby>ruby exception-else-statment.rb
no exception is raised
else code will be executed as no exception is raised.
ensure code will run
F:\worksp\ruby>
Ruby catch
和throw
提供了一種在程式碼中不需要進一步工作的同時從執行中跳出來的方法。
catch
定義了一個標有給定名稱的塊。 它用於跳出巢狀程式碼。 使用catch
語句,塊將被正常執行,直到遇到throw
。
catch
和throw
方法比 rescue
和 raise
快。 因此,更適合使用。
語法:
throw :lablename
#.. this code will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
或者 -
throw :lablename condition
#.. this code will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
範例
#!/usr/bin/ruby
# file : exception-catch-throw.rb
def promptAndGet(prompt)
print prompt
res = readline.chomp
throw :quitRequested if res == "!"
return res
end
catch :quitRequested do
name = promptAndGet("Name: ")
age = promptAndGet("Occupation: ")
# ..
# process information
end
promptAndGet("Name:")
執行上面程式碼,得到以下結果 -
F:\worksp\ruby>ruby exception-catch-throw.rb
Name: Maxsu
Occupation: Occupation
Name:Minsu
F:\worksp\ruby>