Python 和 Java 異常處理對比
當你在編寫程式時,可能由於人為或其它因素導致發生異常後,如果不對異常處理,程式就無法繼續執行。Python語言中也有自己的異常處理,下面我們先看下Java中的異常處理,然後再對比Python中的異常處理,其實它們都大同小異。java 中的異常處理我們不做過多介紹,只是為了和python的異常處理做對比,加深理解。
一、.Java 中的異常處理
java 中 處理異常有五個關鍵字:try catch finally throw throws
try:將可能發生的異常存放到try塊中
catch:對異常進行捕獲
finally:無論是否出現異常都執行
throw:在方法體中丟擲異常
throws:在方法上丟擲異常
java 中對異常的處理更加嚴謹,異常的種類及結構如下
java 中 所有異常的父類為Throwable,Throwable 中有兩個重要的子類:Error(錯誤)和 Exception(異常)
Error 是不可恢復的異常,比如:JVM 溢位。
Exception 又分為兩種異常:檢查時異常和執行時異常。
檢查時異常的特點是需要客戶程式設計師捕獲異常(try)或丟擲異常(throws)讓呼叫著來處理,比如在IO程式設計、執行緒、xml解析應用中的異常都為檢查時異常,需要我們手動捕獲或丟擲異常。
// 檢查時異常
public static void main(String[] args){
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
執行時異常指的是所有的RuntimeException及其子類,特點是無須客戶程式設計師try或throws
// 執行時異常
public static void main(String[] args){
args[1] = "exception"; // 陣列下標訪問越界
}
在實際程式設計中,有時我們會自己定義一些異常來對異常進行處理,java 中 自定義檢查時異常需要繼承Exception 類並覆蓋方法,自定義執行時異常需要繼承 RuntimeException 並覆蓋方法。
// 自定義檢查時異常
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
protected MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
// 測試(需要捕獲或丟擲異常)
public static void main(String[] args){
try {
throw new MyException("自定義檢查時異常");
} catch (MyException e) {
e.printStackTrace();
}
}
}
// 自定義執行時異常
public class MyRuntimeException extends RuntimeException {
public MyRuntimeException() {
super();
}
public MyRuntimeException(String message) {
super(message);
}
public MyRuntimeException(String message, Throwable cause) {
super(message, cause);
}
public MyRuntimeException(Throwable cause) {
super(cause);
}
protected MyRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
// 測試(不需要捕獲或丟擲異常)
public static void main(String[] args){
throw new MyRuntimeException("自定義執行時異常");
}
}
二、Python 中的異常處理
python 中的異常處理相比java來說,要簡單一些,python 中使用四個關鍵字來處理異常
try:捕獲異常,類似於 java 中的 try
except:處理異常,類似於 java 中的 catch
finally:不管是否捕獲到異常都會被執行,類似於 java 中 的 finally
raise:丟擲異常,類似於 java 中的 throw
異常執行流程:
try塊存放可能出現的異常程式碼,如果沒有異常發生,忽略except子句,try子句執行後結束;如果在執行try子句的過程中發生了異常,那麼try子句餘下的部分將被忽略,如果異常的型別和 except 之後的名稱相符,那麼對應的except子句將被執行。最後執行 try 語句之後的程式碼。不管try在執行時,是否發生了異常,finally塊中的內容都會被執行。
python是一種解釋型語言,也就是說沒有編譯,所有它沒有檢查時異常,只有執行時異常,python 中常見異常如下
異常 | 描述 |
---|---|
AssertionError | assert(斷言)語句失敗 |
AttributeError | 訪問一個物件沒有的屬性,比如foo.x ,foo沒有x這個屬性。 |
IOError | 輸入/輸出異常,基本上是無法開啟檔案 |
ImportError | 無法引入模組或者包,基本上是路徑問題 |
IndentationError | 語法錯誤,程式碼沒有正確對齊 |
IndexError | 下標訪問越界,比如當x只有三個元素,卻試圖訪問x[5] |
KeyError | 試圖訪問字典裡不存在的鍵 |
KerboardInterrupt | Ctrl + C 被按下 |
NameError | 使用一個還未被賦值予物件的變數 |
SyntaxError | Python程式碼非法,程式碼不能解釋 |
TypeError | 傳入物件型別與要求的不符 |
UnboundLocalError | 試圖訪問一個還未被設定的區域性變數,基本上是由於另一個同名的全域性變數,導致你以為正在訪問它 |
ValueError | 傳入一個呼叫者不期望的值,即使值的型別是正確的 |
python 中經常用 print() 來列印輸出內容,使用print()丟擲異常,示例如下
print(5/0)
1.raise 丟擲異常
示例:輸入一個數字,如果不是數字則丟擲異常ValueError
inputValue=input("請輸入一個數字:")
type(inputValue)
if inputValue.isdigit():
print(inputValue)
else:
raise ValueError
執行結果1:
請輸入一個數字:1
1
執行結果2:
請輸入一個數字:hello
Traceback (most recent call last):
File “C:\Users\Administrator\Desktop\test.py”, line 6, in
raise ValueError
ValueError
2.try…except…
我們在編寫程式時,可能會出現一些錯誤或異常,如果不進行處理那麼程式就會中止執行,示例如下,訪問字串中下標為20的字元時,會丟擲IndexError異常
str = "hello python"
print(str[20]) # IndexError: string index out of range
執行結果:
Traceback (most recent call last):
File “E:/code/workspace_python/class/python_day03/testError.py”, line 2, in
print(str[20]) # IndexError: string index out of range
IndexError: string index out of range
改寫示例,使用 try…except… 處理異常
str = "hello python"
try:
print(str[20])
except IndexError:
print('error...')
再次執行程式,發生異常後會列印 error…
3.try….except…else
str = "hello python"
try:
print(str[10])
except IndexError:
print('error...')
else:
print('no error...')
執行結果:
o
no error…
將 str[10] 該為str[20],else塊中的內容將不會執行,執行結果為:error…
4.try…except…finally
我們通過一個小案例來看下 try…except…finally 是如何處理異常的,輸入兩個數字然後做除法運算,將可能發生的異常程式碼放到 try 塊中,except 塊中對捕獲到的異常繼續處理
try:
num1 = int(input("請輸入第一個數:"))
num2 = int(input("請輸入第二個數:"))
result = num1 / num2
print("{0} / {1} = num{2}".format(num1, num2, result))
except ValueError as e:
print("ValueError:{0}".format(e))
finally:
print("bye bye");
執行結果1:
請輸入第一個數:10
請輸入第二個數:5
10 / 5 = num2.0
bye bye
執行結果2:第二個數字為字元h,丟擲異常ValueError
請輸入第一個數:1
請輸入第二個數:h
ValueError:invalid literal for int() with base 10: ‘h’
bye bye
執行結果3:除數為0,丟擲異常ZeroDivisionError
請輸入第一個數:1
請輸入第二個數:0
Traceback (most recent call last):
File “E:/code/workspace_python/class/python_day03/testError.py”, line 4, in
result = num1 / num2
ZeroDivisionError: division by zero
bye bye
執行結果3中丟擲了一個ZeroDivisionError異常,我們並沒有對這個異常做處理,異常處理時可以有多個except子句,修改上述程式碼
try:
num1 = int(input("請輸入第一個數:"))
num2 = int(input("請輸入第二個數:"))
result = num1 / num2
print("{0} / {1} = num{2}".format(num1, num2, result))
except ValueError as e:
print("ValueError:{0}".format(e))
except ZeroDivisionError as e:
print("ZeroDivisionError:{0}".format(e))
finally:
print("bye bye");
執行結果:
請輸入第一個數:1
請輸入第二個數:0
ZeroDivisionError:division by zero
bye bye
一個 try 語句可能包含多個except子句,分別來處理不同的特定的異常。最多隻有一個分支會被執行,當有多個except子句時,可以將異常寫在一個元祖裡,改寫上述程式碼
try:
num1 = int(input("請輸入第一個數:"))
num2 = int(input("請輸入第二個數:"))
result = num1 / num2
print("{0} / {1} = num{2}".format(num1, num2, result))
except (ValueError, ZeroDivisionError)as e:
print("Error:{0}".format(e))
finally:
print("bye bye");
執行結果同上
5.傳遞異常
異常處理時,有時候我們在函式或方法內捕獲到了異常,但是又想重新引發它(傳遞異常),可以使用不帶引數的raise語句實現,程式碼如下
class Mcl:
def calc(self, num1, num2):
try:
result = num1 / num2
print("{0} / {1} = {2}".format(num1, num2, result))
return num1 / num2
# 捕獲到異常後不做處理
except ZeroDivisionError as e:
raise
app = Mcl()
app.calc(10, 2)
# 執行結果
# 10 / 2 = 5.0
app = Mcl()
app.calc(1, 0)
# 執行結果(丟擲異常):ZeroDivisionError: division by zero
6.自定義異常
class MyError(Exception):
# 覆蓋Exception的__init__()方法
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
raise MyError("自定義異常!")
執行結果
Traceback (most recent call last):
File “E:/code/workspace_python/class/python_day03/testError.py”, line 7, in
raise MyError(“自定義異常!”)
main.MyError: ‘自定義異常!’