JavaSE——异常处理(异常简介、try-catch-finally、throws、throw)
第4節 異常處理
異常處理學習的目標:
明確說明是異常(重點)
能辨識出常見的異常及其含義(熟悉)
理解異常產生的原理(了解)
能處理異常(重點)
能夠自定義異常(熟悉)
一、什么是異常?
異常是在程序中導致程序中斷運行的一種指令流 。
例如,現在有如下的操作代碼:
public class ExceptionDemo01{ public static void main(String argsp[]){ int i = 10 ; int j = 0 ; System.out.println("============= 計算開始 =============") ; int temp = i / j ; // 進行除法運算 System.out.println("temp = " + temp) ; System.out.println("============= 計算結束 =============") ; } }; 運行結果: ============= 計算開始 ============= Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionDemo01.main(ExceptionDemo01.java:6)以上的代碼在int temp = i / j ;位置處產生了異常,一旦產生異常之后,異常之后的語句將不再執行了,所以現在的程序并沒有正確的執行完畢之后就退出了。
那么,為了保證程序出現異常之后仍然可以正確的執行完畢 ,所以要采用異常的處理機制。
二、處理異常
如果要想對異常進行處理,則必須采用標準的處理格式,處理格式語法如下: try{// 有可能發生異常的代碼段 }catch(異常類型 對象名1) {//異常的處理操作 }catch(異常類型 對象名2) {//異常的處理操作 }... finally{//異常的統一出口 }下面分別來詳細的介紹:
2.1 try+catch的處理流程
一旦產生異常,則系統會自動產生一個異常類的實例化對象;
那么,此時如果異常發生在try語句,則會自動找到匹配的catch語句執行,如果沒有在try語句中,則會將異常拋出;
所有的catch根據方法的參數匹配異常類的實例化對象,如果匹配成功,則表示由此catch進行處理。
下面這張圖將過程解釋的更加具體:
2.2 多異常捕獲
一段代碼塊可能產生多種異常時,需要對多種異常進行捕獲,一般多異常捕獲有三種方式:方式一:分開處理:
package com.kaikeba.objectoriented.exceptionHandling;import java.util.InputMismatchException; import java.util.Scanner;/*** 處理多異常的格式 1:*/ public class Demo2 {public static void main(String[] args) {haha();System.out.println("程序執行完畢,正常結束");}private static void haha() {try {Scanner input = new Scanner(System.in);System.out.println("請輸入一個數字:");int x = input.nextInt();System.out.println("請再輸入一個數字:");int y = input.nextInt();System.out.println(x / y);System.out.println("處理完畢");}catch (ArithmeticException e) {System.out.println("除數不能為0");}catch (InputMismatchException e) {System.out.println("必須是數字");}} }方式二:使用|運算符合并:
package com.kaikeba.objectoriented.exceptionHandling;import java.util.InputMismatchException; import java.util.Scanner;/*** 處理多異常的格式 2:了解*/ public class Demo3 {public static void main(String[] args) {haha();System.out.println("程序執行完畢,正常結束");}private static void haha() {try {Scanner input = new Scanner(System.in);System.out.println("請輸入一個數字:");int x = input.nextInt();System.out.println("請再輸入一個數字:");int y = input.nextInt();System.out.println(x / y);System.out.println("處理完畢");}catch (ArithmeticException | InputMismatchException e) {System.out.println("輸入有誤");}} }方式三:合并為父類異常:
package com.kaikeba.objectoriented.exceptionHandling;import java.util.InputMismatchException; import java.util.Scanner;/*** 處理多異常的格式 3:常用*/ public class Demo4 {public static void main(String[] args) {haha();System.out.println("程序執行完畢,正常結束");}private static void haha() {try {Scanner input = new Scanner(System.in);System.out.println("請輸入一個數字:");int x = input.nextInt();System.out.println("請再輸入一個數字:");int y = input.nextInt();System.out.println(x / y);System.out.println("處理完畢");}catch (RuntimeException e) {//多態System.out.println("輸入有誤");}} }多異常捕獲的注意點:
捕獲更粗的異常不能放在捕獲更細的異常之前;
如果為了方便,則可以將所有異常都使用Exception進行捕獲。
2.3 finally
在進行異常處理之后,在異常的處理格式中還有一個finally語句,此語句將作為異常的統一出口,不管是否產生了異常,最終都要執行此段代碼。除非軟件關閉、電腦關機等強制方法。
觀察如下代碼:
package com.kaikeba.objectoriented.exceptionHandling;public class Demo5 {public static void main(String[] args) {haha();}public static void haha() {try {System.out.println("1");System.out.println("2");System.out.println("3");System.out.println("4");return;}catch (Exception e) {}finally {System.out.println("鋤禾日當午");}} }結果如下:
1 2 3 4 鋤禾日當午即使加了return;還是會執行finally里的代碼。可以這樣理解,return在返回返回值的時候,將返回值進行了一個備份,并做了一些準備工作然后才返回,在這個過程中,finally就執行了 ,所以效果如上所述。
那么這里就涉及到一個常問的面試題 ,查看如下兩段代碼:
package com.kaikeba.objectoriented.exceptionHandling;public class Demo6 {public static void main(String[] args) {Person p = haha();System.out.println(p.age);}public static Person haha() {Person p = new Person();try {p.age = 18;return p;}catch(Exception e){return null;}finally {p.age = 28;}}static class Person{int age;} }結果為:28 package com.kaikeba.objectoriented.exceptionHandling;public class Demo7 {public static void main(String[] args) {int a = haha();System.out.println(a);}public static int haha() {int a = 10;try {return a;}catch(Exception e){return 0;}finally {a = 20;}}static class Person{int age;} }結果為:10解釋:在return的時候,都是對返回的值或者對象進行了一個備份,在準備返回的過程中finally執行了,如果是引用數據類型,p里面保存的是地址,那么備份也備份了這個地址,finally對屬性值修改后,通過地址依然可以訪問到這個修改后的結果;但是如果是基本數據類型,a里面是值,return備份的是10這個值,finally雖然的確也修改了啊變為20,但是這個備份還是10 ,觀察內存圖可能更好理解一點:
補充: 唯一一種在代碼中導致finally不執行的方法——System.exit(0);它的作用是正常退出程序,結束當前正在運行的java虛擬機。
package com.kaikeba.objectoriented.exceptionHandling;public class Demo8 {public static void main(String[] args) {haha();}public static void haha() {try{int a = 10;int b = 0;System.out.println(a/b);}catch(Exception e) {//退出JVMSystem.out.println("出現了異常");System.exit(0);}finally {System.out.println("鋤禾日當午");}} }結果如下:
出現了異常沒有執行finally里的代碼,就結束了。
三、異常體系結構
異常指的是Exception類在Java中存在一個父類Throwable(可能的拋出)。
Throwable存在兩個子類:
Error:表示的是錯誤,是JVM發出的錯誤操作,只能盡量避免,無法用代碼處理;
Exception:一般表示所有程序中的錯誤,所以一般在程序中進行try-catch的處理。
可以看一下JDK API中文手冊里的Exception里的子類:
其中需要特別注意的是RuntimeException類,它是非受檢異常,也叫運行時異常,它只有在程序運行時才能知道是否會發生,事先無法檢查出來,看一下它的子類:
比如數學運算異常、數組索引超出范圍異常等等,在代碼編寫時編譯器是不能察覺的,只有運行時的確發生異常了才會出現。所以異常也可以細分為兩類:受檢異常:
非受檢異常/運行時異常:
RuntimeException與Exception的區別
注意觀察如下方法的源代碼:
Integer類:public static int parseInt(String text throws NumberFormatException
此方法拋出了異常,但使用時卻不需要進行try...catch捕獲處理,原因:
因為 NumberFormatException 并不是Exception的直接子類,而是RuntimeException的直接子類,只要是RuntimeException的子類,則表示程序在操作的時候可以不必使用try-catch進行處理,如果有異常發生,則由JVM進行處理。當然,也可以通過try catch處理。
四、throws關鍵字
在程序中異常的基本處理已經掌握了,但是隨異常一起的還有一個稱為throws關鍵字,此關鍵字主要在方法的聲明上使用,表示方法中不處理異常,而交給調用處處理。
格式:返回值 方法名稱() throws Exception{} package com.kaikeba.objectoriented.exceptionHandling;import java.io.IOException;public class Demo9 {public static void main(String[] args) throws IOException {shutdown("");}public static void shutdown(String text) throws IOException {Runtime.getRuntime().exec(text);}public static void sum(String s1, String s2) {try {int sum = Integer.parseInt(s1) + Integer.parseInt(s2);System.out.println("和是:" + sum);}catch(NumberFormatException e) {}} }異常是應該拋出去還是處理,應該站在哪個角度進行思考:
如果是因為傳參導致的異常,應該通過throws將異常拋出去 。
五、throw關鍵字
throw關鍵字表示在程序中人為的拋出一個異常 ,因為從異常處理機制來看,所有的異常一旦產生之后,實際上拋出的就是一個異常類的實例化對象,那么此對象也可以由throw直接拋出。
看下面這個例子:
package com.kaikeba.objectoriented.exceptionHandling;public class Person {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {if(age<0 || age>180) {RuntimeException e = new RuntimeException("年齡不合理");throw e;}else {this.age = age;}} } package com.kaikeba.objectoriented.exceptionHandling;public class Demo10 {public static void main(String[] args) {Person p = new Person();p.setAge(-1);} }結果如下:
Exception in thread "main" java.lang.RuntimeException: 年齡不合理at com.kaikeba.objectoriented.exceptionHandling.Person.setAge(Person.java:21)at com.kaikeba.objectoriented.exceptionHandling.Demo10.main(Demo10.java:8)Process finished with exit code 1 因為年齡如果輸入不合理,我們就應該告訴執行者年齡有問題,不能像之前一樣只是給它賦一個默認值,但是這里又沒有任何異常的代碼出現,所以為了邏輯上合理,將不合邏輯的年齡手動的拋出異常。六、自定義異常類(了解)
-
編寫一個類,繼承Exception,并重寫一參構造方法 即可完成自定義受檢異常類型。
-
編寫一個類,繼承RuntimeExcepion,并重寫一參構造方法 即可完成自定義運行時異常類型。
例如:
class MyException extends Exception{public MyException(String msg){ //繼承Exception,表示一個自定義異常類super(msg); //調用Exception中有一個參數的構造} }自定義異??梢宰龊芏嗍虑?#xff0c; 例如:
class MyException extends Exception{public MyException(String msg){super(msg) ;//在這里給維護人員發短信或郵件, 告知程序出現了BUG。} } 上述throw拋出異常的例子可以結合自定義類,就是將`RuntimeException`改為自定義的異常類,代碼如下: package com.kaikeba.objectoriented.exceptionHandling.MyExpection;public class AgeRuntimeException extends RuntimeException{{//給程序員發短信}public AgeRuntimeException(String message) {super(message);} } package com.kaikeba.objectoriented.exceptionHandling.MyExpection;public class Person {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {if(age<0 || age>180) {AgeRuntimeException e = new AgeRuntimeException("年齡不合理");throw e;}else {this.age = age;}} } package com.kaikeba.objectoriented.exceptionHandling.MyExpection;public class Demo {public static void main(String[] args) {Person p = new Person();p.setAge(-1);} }結果如下:
Exception in thread "main" com.kaikeba.objectoriented.exceptionHandling.MyExpection.AgeRuntimeException: 年齡不合理at com.kaikeba.objectoriented.exceptionHandling.MyExpection.Person.setAge(Person.java:21)at com.kaikeba.objectoriented.exceptionHandling.MyExpection.Demo.main(Demo.java:6)Process finished with exit code 1七、異常處理常見面試題
1. try-catch-finally中哪個部分可以省略? 答:catch和finally可以省略其中一個,catch和finally不能同時省略。 注意:格式上允許省略catch塊,但是發生異常時就不會捕獲異常了,在開發中也不會這樣去寫代碼。 2. try-catch-finally中,如果catch中return了,finally還會執行嗎? 答:finally中的代碼會執行。 詳解:執行流程:1. 先計算返回值,并將返回值存儲起來,等待返回;2. 執行finally代碼塊;3. 將之前存儲的返回值,返回出去。 需注意:1. 返回值是在finally運算之前就確定了,并且緩存了,不管finally對該值做任何的改變,返回的值都不會改變;2. finally代碼中不建議包含return,因為程序會在上述的流程中提前退出,也就是說返回的值不是try或catch中的值;3. 如果在try或catch中停止了JVM,則finally不會執行,例如停電,或通過如下代碼退出:JVM:System.exit(0);總結
以上是生活随笔為你收集整理的JavaSE——异常处理(异常简介、try-catch-finally、throws、throw)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV——读取视频文件并写入文件
- 下一篇: RNN知识+LSTM知识+encoder