[Java] 9.1. try catch

try catch,控制Java程式中的異常,避免發生錯誤時當機。

 

image/svg+xml9.1. 異常處理流程 – try~catch 異常類別的名稱 ClassCastException 說明了異常發⽣的原因 常⾒的錯誤與異常類別 class Person { String name; // 無其他內容,只是⽤來表⽰繼承⽽已 } class Employee extends Person { // 無內容,只是⽤來表⽰繼承⽽已 } class Main { public static void main( String [] args) { Person p = new Person (); Employee e = ( Employee ) p ; } } 編譯階段 c:\javac Main.jav a 執⾏階段 c:\java Mai n 執⾏結果 Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Employee at Main.main(Main.java:4) class Main { public static void main( String [] args) { Person p = new Person (); p.name = "Jack" ; try { Employee e = ( Employee ) p ; } catch ( ClassCastException e ){ System.out.println( " 抓到轉型的異常了 !! " ); } System.out.println( " 我的名字是 " + p . name ); } } 執⾏結果 抓到轉型的異常了 !! 我的名字是 Jack class Main { public static void main( String [] args) { Person p = new Person (); p.name = "Jack" ; try { Employee e = ( Employee ) p ; } catch ( ClassCastException e ){ System.out.println( " 抓到轉型的異常了 !! " ); } System.out.println( " 我的名字是 " + p . name ); } } class Main { public static void main( String [] args) { Person p = new Person (); p.name = “Jack" ; try { Employee e = ( Employee ) p ; } catch ( ClassCastException e ){ System.out.println( " 抓到轉型的異常了 !! " ); } System.out.println( " 我的名字是 " + p . name ); } } class Main { public static void main( String [] args) { Person [] ps = new Person [ 3 ]; ps[ 0 ] = new Person(); ps[ 1 ] = new Person(); ps[ 2 ] = new Person(); ps[ 3 ] = new Person(); } } 執⾏時成功 c:\javac Main.jav a 執⾏時錯誤 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 at Main.main(Main.java:8) class Main { public static void main( String [] args) { Person [] ps = new Person [ 3 ]; ps[ 0 ] = new Person(); ps[ 1 ] = new Person(); ps[ 2 ] = new Person(); try { ps[ 3 ] = new Person(); } catch ( ArrayIndexOutOfBoundsException e ){ System.out.println( " 抓到超出陣列索引值的異常了 !!" ); } } } 以下是常⾒的錯誤( Error )與異常( Exception )類別的繼承樹狀圖,在此圖中,可以了解每個錯誤與 異常物件的繼承關係。雖然錯誤與異常是兩個不同體系的類別,但它們皆是繼承了 Throwable ,因此不 論是錯誤或異常發⽣的時候,皆是只拋出錯誤或異常的⽅式進⾏的。 class Main { public static void main( String [] args) { Employee [] es = new Employee [ 3 ]; es [ 0 ] = new Employee(); es[ 1 ] = new Employee(); es[ 2 ] = new Employee(); Person e1 = new Person (); //Employee e1 = new Employee(); try { es[ 3 ] = ( Employee ) e1 ; } catch ( ArrayIndexOutOfBoundsException e){ System.out.println( " 抓到超出陣列索引值的異常了 !!" ); } } } 執⾏時異常 Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to Employee at Main.main(Main.java:12) class Main { public static void main( String [] args) { Employee [] es = new Employee [ 3 ]; es[ 0 ] = new Employee(); es[ 1 ] = new Employee(); es[ 2 ] = new Employee(); Person e1 = new Person (); //Employee e1 = new Employee(); try { e s[ 3 ] = ( Employee ) e1 ; } catch ( ClassCastException e){ System.out.println( " 抓到轉型的異常了 !!" ); } catch ( ArrayIndexOutOfBoundsException e){ System.out.println( " 抓到超出陣列索引值的異常了 !!" ); } System.out.println( "try~catch 後的程式 " ); } } 執⾏結果 抓到轉型的異常了 !! try~catch 後的程式 class Main { public static void main( String [] args) { Employee [] es = new Employee [ 3 ]; es[ 0 ] = new Employee(); es[ 1 ] = new Employee(); es[ 2 ] = new Employee(); Person e1 = new Person (); //Employee e1 = new Employee(); try { e s[ 3 ] = ( Employee ) e1 ; } catch ( Exception e){ System.out.println( " 只要是異常, Exception 都是可以補抓到的 !!" ); } System.out.println( "try~catch 後的程式 " ); } } 執⾏結果 只要是異常, Exception 都是可以補抓到的 !!   try~catch 後的程式             class Main { public static void main( String [] args) { Employee [] es = new Employee [ 3 ]; es[ 0 ] = new Employee(); es[ 1 ] = new Employee(); es[ 2 ] = new Employee(); Person e1 = new Person(); //Employee e1 = new Employee(); try { es[ 3 ] = (Employee)e1; } catch ( Exception e){ System.out.println( " 只要是異常, Exception 都是可以補抓到的 !!" ); } catch ( ClassCastException e){ System.out.println( " 抓到轉型的異常了 !!" ); } catch ( ArrayIndexOutOfBoundsException e){ System.out.println( " 抓到超出陣列索引值的異常了 !!" ); } } } 執⾏結果 Main.java:15: error: exception ClassCastException has already been caught }catch(ClassCastException e){ ^ Main.java:17: error: exception ArrayIndexOutOfBoundsException has already been caught }catch(ArrayIndexOutOfBoundsException e ^ 2 errors class Main { public static void main( String [] args) { Employee [] es = new Employee [ 3 ]; es[ 0 ] = new Employee(); es[ 1 ] = new Employee(); es[ 2 ] = new Employee(); Person e1 = new Person(); //Employee e1 = new Employee(); try { es[ 3 ] = (Employee)e1; } catch ( ClassCastException e){ System.out.println( " 抓到轉型的異常了 !!" ); } catch ( ArrayIndexOutOfBoundsException e){ System.out.println( " 抓到超出陣列索引值的異常了 !!" ); } catch ( Exception e){ System.out.println( " 只要是異常, Exception 都是可以補抓到的 !!" ); } } } class Main { public static void main( String [] args) { Employee [] es = new Employee [ 3 ]; es[ 0 ] = new Employee(); es[ 1 ] = new Employee(); es[ 2 ] = new Employee(); Person e1 = new Person(); try { es[ 3 ] = ( Employee ) e1 ; } catch ( ArrayIndexOutOfBoundsException e){ System.out.println( " 抓到超出陣列索引值的異常了 !!" ); } finally { System.out.println( " finally 保證程式⼀定會執⾏,即使這可能是您程到的最後執⾏的結果 " ); } System.out.println( " try~catch 後的程式 " ); } } 錯誤 說明 AssertionError 當陳述式的 boolean 測試回傳是   false 的時 候發⽣。 ExceptionInInitializerError 嘗試初始靜態變數或在靜態區塊內發⽣錯 誤時所拋出的。 NoClassDefFoundError 嘗試執⾏⼀個沒有 main() ⽅法的類別檔。 StackOver f owError 通常是在⼀個⽅法遞迴地太深的時候發 ⽣。 ArithmeticException 算術錯誤時發⽣。例如除以 0 ClassCastException 轉型失敗時拋出的異常物件。 ArrayIndexOutOfBoundsException 嘗試使⽤不存在的索引值去存取⼀個陣列 時,所拋出的異常物件。 NumberFormatException 當⽅法轉換⼀個 String 成數字時,其所接放 String 卻不能如預期地進⾏轉換時發⽣。 IllegalStateException 當環境的狀態和正在嘗試進⾏的運算不相 符的時候拋出的。例如,使⽤已經關閉的 Scanner NullPointerException 嘗試從變數中取出物件,但讓變數中只有 null 時發⽣。 EOFException 嘗試讀取檔案,但此檔已無資料可以讀取 時發⽣。 FileNotFoundException 開啟⼀個不存在的檔時發⽣。 InterruptedException 執⾏緒( Thread )被中斷時發⽣。 J9_1_1 – Person.java 4. 轉型失敗 !! J9_1_2 – Main.java 1. 這是⼈員類別( Person )。 J9_1_1 – Employee.java J9_1_1 – Main.java 2. 這是員⼯類別( Employee ),其繼承⾃⼈員類別,這表⽰ 員⼯物件可透過多型(參考第六章)轉型為⼈員型別的物件。 3. 在此建立的是⼈員物件。 4. 把非擁有員⼯型別的物件,向下轉型(即強迫轉型)為員⼯類別。 5. 即使在⼈員類別不能轉型成員⼯類別的情況下,編譯還是可以成功的。因 為我們已經透過向下轉型(即強迫轉型),來告訴編譯器⼀定可以轉型成功。 6. 執⾏時卻發現⼈員物件並不能轉型為員⼯物件,需發⽣ 轉型失敗的情況,如此程式即會當機,若不想讓程式當機⼜要 如何控制這個錯誤呢?或許告知使⽤此程式的⼈員⼀個特定訊 息,這個錯誤是我們控制範圍內的,如此也⾏! 7. 特別要注意的是當我們處理完這個異常後,在 try~catch 之後的 程式是會繼續執⾏下去的,在此會正常轉出⼈員名稱- Jack 5. catch 是我們捕抓的程式區塊,當成功捕抓後,就可以進⾏⼀ 些處理。現在我們的處理很單純,就是輸出⼀段訊息⽽已,告訴執 ⾏此程式的⼈員,這裡發⽣了 轉型異常 6. catch 後⾯有 ⼩括號?!沒關 係,先照著寫,等 會就會為您解釋這 是什麼。它寫起來 就像參數⼀樣。 3. 這⼀⾏程式曾經轉型失敗,⽽讓程式當機的⼀⾏程式,現在我們把 它將在屬於 try 的⼤括號({})中。意思是嘗試著去捕抓的意思。 2. 在此使⽤ try~catch 補抓轉型異常。 1. 注意,建立的是⼈員物件( Person )。 J9_1_2 – Main.java 1. 注意,建立的是⼈員物件( Person )。 2. try 程式區塊包含著可能產⽣異常的程式。 3. 轉型失敗,產⽣⼀個異常物件。 4. catch 即是⽤來捕抓此異常物 件的,在 catch 中,以參數型別- ClassCastException 比對這個 異常物件是否為此型別的物件。 5. 若是,則將這個物件接收,並放入接收變數 e 中。 Obj Obj J9_1_2 – Main.java 1. 在此建立⼀個不能轉型成員⼯型別 Employee )的⼈員物件( Person )。 . JVM 發現這是⼀個轉型失敗的問題。 3. 那就應該拿出代表此異常的類別- ClassCastException ,並建立這個類別 的物件,將它拋出去。 4. 但因為我們使⽤了 try~catch ,因此會去比對有 沒有可以補抓此轉型異常物件的 catch 項⽬(即 catch 參數中有 符合此異常物件的類別)。 5. 若比對成功則將這個物件接收, 並放入接收變數 e 中。 JVM Obj Obj J9_1_2 – Main.java 1. 在此建立⼀個不能轉型成員⼯型別 Employee )的⼈員物件( Person )。 2. 這裡剛好裝下 3 位⼈員物件。 3. 若執意放入第 4 個物件於索引位置 3 中,這時會因索引位置 3 是不存在的,當使⽤超過陣列的最⼤索引值位置時,將會發⽣異常 並拋出異常物件,如此⼜讓程式當機了。聰明的您看出端倪了嗎? 在發⽣異常時若不使⽤ try~catch 捕抓,則會這個異常物件列印 並顯⽰在畫⾯上,同時也會說明這個異常物件的類別名稱 ArrayIndexOutOfBoundsException 。那我們是否要對此類型 的異常作些什麼呢?好讓程式不要⼜當機了。 J9_1_4 – Main.java 1. 這個陣列最多只能夠裝下 3 位⼈員物件( Person )。 2. 這裡剛好裝下 3 位⼈員物件。 3. 在此已知使⽤不存在的索引位置 3 將會發⽣異常並拋出 ArrayIndexOutOfBoundsExceptions 類別型別的異常物件,在此類 別的名稱即可看出問題所在, “Array Index Out Of Bounds” 即說 明了陣列索引值超出了陣列 3 格空間的邊界,因此產⽣此異常。 4. 最後在 catch 中,即可透過 ArrayIndexOutOfBoundsExceptions 類別型別捕抓到這個異常物件,以進⾏後續異常的處理。 這個程式再⼀次的展現了不同的異常情況, Java 都會為我們準到⼀些表⽰異 常情況的類別,並在發現異常狀況時,依照異常的種類找出表⽰此異常的類 別,在建立異常物件後將異常物件拋出;此時,就可以使⽤ try~catch 將異 常捕抓起來並處理掉。 Throwable Error Exception RuntimeException ClassCastException LinkageError VirtualMachineError StackOver f owError OutOfMemoryError ArithmeticException IndexOutOfBoundsException EOFException FileNotFoundException IOException InterruptedException NullPointerException IllegalArgumentException IllegalStateException ExceptionInInitializerError NoClassDefFoundError AssertionError ArrayIndexOutOfBoundsException NumberFormatException J9_1_5 – Main.java 1. 這個陣列最多只能夠裝下 3 位員⼯物件( Employee )。 2. 若建立⼈員物件,則會後續程式會發⽣ 轉型異常(