微信小程式發起請求
異常
學習目標:
- 能夠區分程式中的異常和錯誤
- 說出異常的分類
- 說出虛擬機器處理異常的方式
- 列出常見的四個執行期異常
- 能夠使用try-catch關鍵字處理異常
- 能夠使用throws關鍵字處理異常
*能夠自定義異常類
*能夠處理自定義異常類
異常的概念
在程式中,程式出現啦不正常的現象,執行時丟擲的程式中斷的問題,屬於異常現象,會導致JVM的非正常停止.異常本身是一個類,產生異常就是建立啦異常物件並丟擲異常的方式來中斷程式
備註: 異常指的不是語法錯誤,如果是語法錯誤,編譯不會通過,不會產生位元組碼檔案,根本不會丟擲異常
Throwable體系:
- Error:嚴重的錯誤Error,無法通過異常處理的錯誤,好比絕症,只能是事先預防.
- Exception: 異常,異常產生後程序員可以通過程式碼的方式進行糾正處理,使程式能夠正常執行下去
異常的處理:
java異常處理的五個關鍵字:try catch finally throw throws
丟擲異常throw
當我們在編寫程式時,我們必須先考慮可能出現的問題的情況.
比如:在定義方法時,方法需要接收引數,那麼對於呼叫者來說,當呼叫方法的時候需要接收引數,首先需要對引數資料進行合法判斷,若資料不合法,就應該告訴呼叫者,傳遞合法的資料進來,這時候就需要使用丟擲異常的方式告訴呼叫者
在java中,提供啦一個關鍵字throw,他用來丟擲一個指定的異常物件.
步驟:
- 常見一個異常物件,封裝一些提示資訊(資訊可以自己編寫)
- 需要將這個異常物件告知給呼叫者,通過關鍵字throw就可以完成,throw跑出的是一個物件,一般用在方法內,用來丟擲一個具體的異常物件,將這個物件丟擲給呼叫者處,並結束當前方法的執行.
使用格式:
throw new 異常類名(引數);
示例:
//給呼叫者丟擲一個空指標異常
throw new NullPointer(引數);
* throw關鍵字 * 作用: * 可以使用throw關鍵字在指定的方法中丟擲指定的異常 * 使用格式: * throw new XxxException("異常產生的原因"); * 注意: * 1. throw關鍵字寫在方法內部 * 2. throw關鍵字後面new的物件必須是Exception或者Exception的子類物件 * 3. throw 關鍵字丟擲指定的異常物件,我們必須要去處理這個異常物件 * throw關鍵字後面建立的是RuntimeException或者RuntimeException的子類物件,我們可以選擇不處理,交給JVM(列印異常物件.) * throw關鍵字後面如果是編譯異常,我們必須處理 ,要麼丟擲throws,要麼捕獲try_catch_finally
方法傳遞
Objects非空判斷
在該類中,提供一些靜態的使用方法,這是方法null-safe (空指標安全)或者null-tolerant(容忍空指標的),那麼在它的原始碼中,對物件的null值進行啦丟擲異常的操作
- public static
T requireNonNull(T obj, String message )
宣告異常處理--throws
宣告異常: 將問題標識出來,報告給呼叫者,如果方法內通過throw丟擲了一個編譯期異常,又沒有通過捕獲進行處理(try..catch),那麼必須通過throws進行宣告,讓呼叫者去處理.
關鍵字throws 運用在方法的宣告上,用於表示不處理異常,提醒呼叫者該方法的呼叫者攜帶的是有異常資訊的,誰呼叫誰處理
宣告異常處理的格式:
修飾符 返回修飾符 方法名(引數列表) throws 異常類名1,異常類名2..){}
示例程式碼:
public class DemoThrows{
public static void main(String[] args){
read("C:/a.txt");
}
public static void read(String path) throws FileNotFoundsException{
//校驗 如果你傳遞的路徑不是以.txt結尾的,丟擲呼叫者檔案找不到異常
if(!path.endsWith(".txt")){
//丟擲一個檔案找不到異常
throw new FileNotFoundException("檔案找不到");
}
}
}
throws關鍵字,異常處理的第一種方式: 宣告異常處理,交給方法的的呼叫者來處理
作用:
當方法內部丟擲了異常物件的時候,那麼我們就必須處理這個異常物件
可以使用throws關鍵字處理異常物件,會把異常物件宣告丟擲給方法的呼叫者(自己不處理,讓別人處理),最終交給虛擬機器處理- -- >中斷處理
格式:
修飾符返回值型別方法名(引數列表) throws AaaException, BbbException.... {
throw new AaaException( "產生的原因");
throw new BbbException("產生的原因");
注意事項:
- throws 關鍵字必須寫在方法宣告處
- throws 關鍵字後面宣告的異常必須是Except ion或者是Exception類的子類
3.方法內部如果丟擲了多個異常物件,那麼throws後面也必須宣告對應的多個異常
如果丟擲的多個異常物件有子父類關係,那麼直接宣告對應的多個異常
4.呼叫一個宣告丟擲異常的方法,我們必須處理這個異常
要麼繼續使用throws往上拋,拋給方法的呼叫者,最終交給虛擬機器JVM
要麼捕獲try--catch
try--catch
如果異常出現的話,會立即終止程式
- 如果使用throws關鍵字來宣告式處理,由該方法的呼叫者來處理(很危險)
- 在方法中使用try-- catch的語句塊來處理異常
try--catch的方式就是捕獲
捕獲異常:java中對異常有針對性的語句塊來進行捕獲,可以對出現的異常進行指定的方式處理.
捕獲異常的方式:
try{
//編寫的程式有異常
//異常語句;
}catch(異常型別 e){
//處理異常的邏輯程式碼
}
catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理
備註: try和catch都不能單獨使用,一般建議連用
程式碼演示:
public class TryCatchDemo{
public static void main(String[] args){
try{
read("C:\\a.txt");
}catch(FileNotFoundException e){//try丟擲的是什麼型別的異 常型別資料,就捕獲什麼型別的異常進行處理
//列印異常資訊
System.out.println(e);
}
System.out.println("程式往下載入了!");
}
public static void read(String path) throws FileNotFoundsException{
if(path.endsWith("D:")){
throw new FileNotFoundsException("碟符不對,檔案未找到");
}
}
}
如何獲取異常的資訊
Throwable類裡定義啦一些常用的API方法
- public String getMessage():獲取異常的描述資訊,原因(提示給使用者看,提示錯誤原因)
- public String toString():獲取異常的型別,異常的描述資訊
- public void printStackTrace():列印異常的跟蹤棧資訊並且輸出到控制檯中
包含了異常的型別,資訊,位置
finally語句塊
finally:有些特定的程式碼,無論有沒有異常發生,都要執行,當程式發生異常時,會引發程式的跳躍性,導致有一些程式碼載入不到,而finally語句塊就是用來解決這類問題的,在finally語句塊中存放的程式碼一般都是會被執行到的
什麼樣的程式碼需要最終一定要執行到?
比如說,在try中打開了一些物理資源(磁碟檔案/網路連線/資料的連結),我們一般使用後要關閉掉,可以使用finally語句塊來實現
finally語句塊的語法格式:
try{
//
}catch(異常型別 e){
//......
}
......
finally{
//......
}
}
備註:中間的catch語句可以省略,finally不能單獨使用,建議連用.
程式碼演示:
public class FinallyDemo{
public static void main(String[] args){
try{
System.out.println("開啟IO流");
readFile("C:\a.doc");
}catch(IOException e){
e.printStackTrace();
}finally{
System.out.println("不管程式如何執行,此處程式碼塊一定會被載入到");
System.out.println("關閉IO流");
}
}
public static void readFile(String path) throws IOException{
if(!path.endsWith(".txt")){
throw new IOException("檔案未找到異常");
}
}
}
備註:
1. 如果finally語句塊中有return語句,永遠返回的是finally語句塊中的結果值
2. 當只有在try或者catch中呼叫退出JVM 的相關方法,此時finally才不會被執行到,否則finally永遠會被執行.
##### 異常的注意事項
當程式中出現了多個異常那麼該如何捕獲又該如何處理?
1. 多個異常分別處理
2. 多個異常一次捕獲,多次處理
3. 多個異常一次捕獲,一次處理
一般都是使用一次捕獲,多次處理的方式,格式如下:
try{
//可能出現的異常程式碼,多個異常
}catch(異常型別A e){
//處理異常A的邏輯程式碼
}catch(異常型別B e){//當try中出現B異常的時候,就用該catch捕獲
//處理異常的邏輯
}
...
...
注意: 這種異常處理方式,要求多個catch的異常型別不同,並且若catch中的多個異常之間存在子父類關係,那麼子類異常的處理在父類異常的處理的上面進行處理,父類異常的處理在下面
- 執行時異常被丟擲可以不處理,即不捕獲也不宣告丟擲
- 如果finally中有return語句,那麼永遠返回的是finally語句塊中的值
*如果父類丟擲了多個異常,子類重寫父類方法時.丟擲的和父類相同的異常或者是父類異常的子類異常或者不丟擲異常 - 父類方法如果沒有丟擲異常,子類重寫該方法時也不會丟擲異常.如果此時子類方法內產生了異常,只能捕獲處理,不能宣告丟擲
自定義異常類的練習
模擬註冊操作,如果使用者存在,則丟擲異常並提示:親,您的名字已經註冊啦,再換個名字吧!
//首先 定義一個註冊異常類 ,業務邏輯異常類
public class RegisterException extends RuntimeException{
//空參構造
public RegisterException(){}
//有參構造
public RegisterException(String message){
super(mwssage);
}
}
public class Demo{
//使用陣列模擬資料庫 已存在多個賬戶名稱
public static string[] names = {"小孫","小王","小趙"};
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
String name = scan.next();
//校驗賬戶是否被註冊過
try{
//可能會引發異常的程式碼
checkName(name);
System.out.println("註冊成功!");
names=Arrays.copyOf(names,names.length+1);
name是[names.length-1] =name;
}catch(RegisterException e){
//異常的處理邏輯
e.printStackTrace();
}
}
public static boolean checkName(String username) throws RegisterException{
for(String name : names){
if(name.equals(username)){
//表名名字已經被註冊過,丟擲註冊異常
throw new RegisterException("親,你的名字已經被註冊了,你再換個名字吧!");
}
}
return true;
}
}