## 22.異常處理
在印度,法律不適用于富裕和政治階層。 他們可以做任何事情并擺脫它。 盡管我們的法律規定賄賂是非法的,但幾乎沒有印度人沒有賄賂。 自由言論和博客作者是無情的目標。 這里的一切都是例外,法律大多只是紙上寫的。 對于腐敗的富人和政客,我們可能無能為力,但至少我們可以在 Ruby 中處理異常! 讓我在本節中解釋如何在 Ruby 編程中處理異常。
讓我們編寫一個名為 [code / division_exception.rb](code/division_exception.rb) 的程序,該程序會因被零除而中斷。 打開文本編輯器,在下面鍵入給定的代碼并運行它
```rb
# division_exception.rb
puts 67 / 0
```
輸出量
```rb
division_exception.rb:3:in `/': divided by 0 (ZeroDivisionError)
from division_exception.rb:3:in `<main>'
```
如你所見,你將獲得一個異常作為輸出。 看到常數`ZeroDivisionError`。 我們將在幾個示例中看到的使用。 因此,當 Ruby 解釋器注意到它無法處理某些內容時,就會引發異常。
如果我們把例外扔給已經為開發一個程序付出了數百萬美元的客戶的客戶,那將不是什么好事。 我們寧愿嘗試提供他們可以理解的內容。 因此,在下面顯示的示例 [code / rescue.rb](code/rescue.rb) 中,我們看到了如何處理此異常。 在文本編輯器中鍵入以下程序并運行它
```rb
# rescue.rb
begin
puts 67 / 0
rescue
puts "We are unable to proceed due to unavoidable reasons :("
end
```
Output
```rb
We are unable to proceed due to unavoidable reasons :(
```
正如你看到的那樣,你看到的不是友好的`ZeroDivisionError`輸出,而是一條友好的消息,指出由于不可避免的原因其無法繼續進行。 訣竅是,如果你認為在`begin`和`end`塊周圍的代碼中可能會發生某些異常,如下所示
```rb
begin
puts 67 / 0
end
```
然后將出現異常時需要處理的代碼放在一個名為`rescue`的關鍵字之后,如下所示
```rb
begin
puts 67 / 0
rescue
puts "We are unable to proceed due to unavoidable reasons :("
end
```
發生異常時,`rescue`下面的代碼開始執行。 而已! 好了,現在你如何粗略地處理異常。
現在讓我們看一種捕獲或從異常中解脫出來的改進方法。 參見下面的代碼 [rescue_1.rb](code/rescue_1.rb) ,鍵入并執行
```rb
# rescue_1.rb
begin
puts 67 / 0
rescue ZeroDivisionError
puts "Oh nooo! boom thata has cursed us!!!!!"
end
```
Output
```rb
Oh nooo! boom thata has cursed us!!!!!
```
你會看到 Boom Thata(眾神)詛咒的輸出。 不必為此擔心,Boom Thata 是我的朋友,并且會和他交談以扭轉局勢。 在這里,我們將類似`rescue ZeroDivisionError`的代碼放入其中,告訴它如果僅發生零除法錯誤,則可以進行挽救。 如果發生其他異常,由于我們僅處理`ZeroDivisionError`,你將不會因此而被救出。
為了顯示我的意思,請在下面鍵入程序( [rescue_2.rb](code/rescue_2.rb) )并執行它
```rb
# rescue_2.rb
begin
"abc" * "def"
rescue ZeroDivisionError
puts "Oh nooo! boom thata has cursed us!!!!!"
end
```
Output
```rb
Traceback (most recent call last):
1: from rescue_2.rb:4:in `<main>'
rescue_2.rb:4:in `*': no implicit conversion of String into Integer (TypeError)
```
在這里,我們仍然在終端上出現錯誤,因為將兩個字符串相乘會產生一個不同的錯誤,稱為`TypeError`,如你在輸出中看到的,而不是`ZeroDivisionError`。 并且在程序中,我們僅針對`ZerodivisionError`進行了救援。
假設你要打印出異常。 出于調試目的或其他目的。 那么該怎么做。 以下程序向你展示了這一點。 鍵入程序 printing_exception.rb 并運行它
```rb
# printing_exception.rb
begin
puts 67 / 0
rescue => e
puts "The following exception has occured:"
p e
end
```
Output
```rb
The following exception has occured:
#<ZeroDivisionError: divided by 0>
```
如你所見,你可以打印一個異常。 只要注意`p e`行,它就是我們在其中打印異常的地方。 `e`是例外對象,`p`是看跌期權的簡稱。 希望你注意到此代碼`rescue ? e`將異常推送到變量`e`中。 `e`就是這種例外。
在下一個示例中,我們將看到如何追溯異常。 例外情況是,在現實世界中拋出的程序可能會被埋在多個層次中。 為了找到答案,你最好需要追溯它。 在文本編輯器中鍵入以下程序,然后運行它。
```rb
# backtracing_exception.rb
begin
puts 67 / 0
rescue => e
p e.backtrace
end
```
Output
```rb
["backtracing_exception.rb:4:in `/'", "backtracing_exception.rb:4:in `<main>'"]
```
我們正在使用`p e.backtrace`打印反向跟蹤。 如果你可以注意到輸出,則表明第 4 行發生了異常。如果在文本編輯器中顯示了行號,則可以立即識別該行并進行調試。
接下來(第二部分輸出)表示 main 中發生了異常。 你可能想知道什么是主要的? 它在你的文本編輯器中首先運行的程序稱為 main。
### 22.1 異常和線程
我們已經在單線程的普通程序中看到了例外,但是 Ruby 是一種多線程編程語言。 讓我們看看異常和線程如何混合和表現。 鍵入程序 [thread_exception_true.rb](code/thread_exception_true.rb) 并運行它
```rb
#!/usr/bin/ruby
# thread_exception_true.rb
t = Thread.new do
i = 5
while i >= -1
sleep(1)
puts 25 / i
i -= 1
end
end
t.abort_on_exception = true
sleep(10)
puts "Program completed"
```
Output
```rb
5
6
8
12
25
thread_exception_true.rb:8:in `/': divided by 0 (ZeroDivisionError)
from thread_exception_true.rb:8:in `block in <main>'
```
如你所見,程序拋出`ZeroDivisionError`異常,當`i`的值變為零且需要除以 25 時,會在`while`循環中發生這種情況。 注意`t.abort_on_exception = true`行,這里我們告訴程序在出現異常時中止或停止。 如果所有其他線程并行運行,這將停止所有其他線程。 假設你有一個多線程程序,其中必須所有線程都必須無例外地運行,并且線程之間是相互依賴的,那么最好以這樣的方式編寫代碼:當異常發生時程序中止 在其中一根線中凸起。
可以說,我們編寫的程序可以忽略線程上的異常,而其他線程可以輕松運行,然后在 [thread_exception_false.rb](code/thread_exception_false.rb) 下看到程序中的`t.abort_on_exception = false`行。 在這里,我們指定`t.abort_on_exception = false`,以便程序運行,當發生異常時,特定線程停止運行,而其他線程繼續運行,好像什么也沒發生。
```rb
#!/usr/bin/ruby
# thread_exception_false.rb
t = Thread.new do
i = 5
while i >= -1
sleep(1)
puts 25 / i
i -= 1
end
end
t.abort_on_exception = false
sleep(10)
puts "Program completed"
```
Output
```rb
5
6
8
12
25
Program completed
```
### 22.2。 引發異常
我們已經看到了如何捕獲異常并對其進行處理。 但是,如果我們想提出自己的例外情況怎么辦? 在文本編輯器中鍵入程序 [raise.rb](code/raise.rb) 并執行它。
```rb
# raise.rb
puts "Enter a number 1 - 10:"
num = gets.to_i
raise "You did not enter right num" unless (1..10).include? num
```
Output
```rb
Enter a number 1 - 10:
25
raise.rb:5:in `<main>': You did not enter right num (RuntimeError)
```
從輸出中可以看到,如果輸入的任何數字不是從 1 到 10,程序都會引發異常。請參見代碼段`raise "You did not enter right num"`,這就是在 Ruby 中引發異常的全部過程。 關鍵字`raise`后跟一個對象,在這種情況下,我們給出了一個字符串,但是如果我們給出一個常量(引發異常的規范),那將是很好的。 [raise_1.rb](code/raise_1.rb) 下面的程序顯示了如何處理自己的異常,該異常與你先前編寫的救援程序沒有什么不同。
```rb
# raise_1.rb
def number_thing(num)
raise "You did not enter right num" unless (1..10).include? num
puts "You entered #{num} :)"
end
puts "Enter a number 1 - 10:"
num = gets.to_i
begin
number_thing(num)
rescue
puts "You may have not entered number in valid range"
end
```
Output
```rb
Enter a number 1 - 10:
25
You may have not entered number in valid range
```
- 前言
- 紅寶石
- 先決條件
- 1.安裝 Ruby
- 2.在線資源
- 3.入門
- 4.比較與邏輯
- 5.循環
- 6.數組
- 7.哈希和符號
- 8.范圍
- 9.功能
- 10.可變范圍
- 11.類&對象
- 12.安全導航
- 13.打破大型程序
- 14.結構和 OpenStruct
- 15. Rdoc
- 16. Ruby 樣式指南
- 17.模塊和混入
- 18.日期和時間
- 19.文件
- 20. Proc,Lambda 和塊
- 21.多線程
- 22.異常處理
- 23.正則表達式
- 24.寶石
- 25.元編程
- 26.基準
- 27.測試驅動開發
- 28.觀察者模式
- 29.模板模式
- 30.工廠模式
- 31.裝飾圖案
- 32.適配器模式
- 33.單例模式
- 34.復合模式
- 35.建造者模式
- 36.策略模式
- 贊助商
- 捐
- 人們怎么說
- 版權
- 取得這本書