1. 程式人生 > >Python 和 Java 異常處理對比

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: ‘自定義異常!’