第一章 異常1、Throwable 類是java語言中的所有錯誤和異常的基類。2、 java.lang.Throwable:類是 Java 語言中所有錯誤或異常的超類。 代碼示例: 1 public class Demo01Exception { 2 public static void main(String[] args) /*throws ParseException*/ { 3 //Exception:編譯期異常,進(jìn)行編譯(寫代碼)java程序出現(xiàn)的問題 4 /*SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//用來格式化日期 5 Date date = null; 6 try { 7 date = sdf.parse("1999-0909");//把字符串格式的日期,解析為Date格式的日期 8 } catch (ParseException e) { 9 e.printStackTrace(); 10 } 11 System.out.println(date);*/ 12 13 //RuntimeException:運(yùn)行期異常,java程序運(yùn)行過程中出現(xiàn)的問題 14 /*int[] arr = {1,2,3}; 15 //System.out.println(arr[0]); 16 try { 17 //可能會出現(xiàn)異常的代碼 18 System.out.println(arr[3]); 19 }catch(Exception e){ 20 //異常的處理邏輯 21 System.out.println(e); 22 }*/ 23 24 /* 25 Error:錯誤 26 OutOfMemoryError: Java heap space 27 內(nèi)存溢出的錯誤,創(chuàng)建的數(shù)組太大了,超出了給JVM分配的內(nèi)存 28 */ 29 //int[] arr = new int[1024*1024*1024]; 30 //必須修改代碼,創(chuàng)建的數(shù)組小一點 31 int[] arr = new int[1024*1024]; 32 System.out.println("后續(xù)代碼"); 33 } 3、異常的產(chǎn)生過程解析 第二章 異常的處理Java異常處理的五個關(guān)鍵字:try、catch、finally、throw、throws 2.1 throw關(guān)鍵字 作用: 代碼示例: 1 public class Demo03Throw { 2 public static void main(String[] args) { 3 //int[] arr = null; 4 int[] arr = new int[3]; 5 int e = getElement(arr,3); 6 System.out.println(e); 7 } 8 /* 9 定義一個方法,獲取數(shù)組指定索引處的元素 10 參數(shù): 11 int[] arr 12 int index 13 以后(工作中)我們首先必須對方法傳遞過來的參數(shù)進(jìn)行合法性校驗 14 如果參數(shù)不合法,那么我們就必須使用拋出異常的方式,告知方法的調(diào)用者,傳遞的參數(shù)有問題 15 注意: 16 NullPointerException是一個運(yùn)行期異常,我們不用處理,默認(rèn)交給JVM處理 17 ArrayIndexOutOfBoundsException是一個運(yùn)行期異常,我們不用處理,默認(rèn)交給JVM處理 18 */ 19 public static int getElement(int[] arr,int index){ 20 /* 21 我們可以對傳遞過來的參數(shù)數(shù)組,進(jìn)行合法性校驗 22 如果數(shù)組arr的值是null 23 那么我們就拋出空指針異常,告知方法的調(diào)用者"傳遞的數(shù)組的值是null" 24 */ 25 if(arr == null){ 26 throw new NullPointerException("傳遞的數(shù)組的值是null"); 27 } 28 29 /* 30 我們可以對傳遞過來的參數(shù)index進(jìn)行合法性校驗 31 如果index的范圍不在數(shù)組的索引范圍內(nèi) 32 那么我們就拋出數(shù)組索引越界異常,告知方法的調(diào)用者"傳遞的索引超出了數(shù)組的使用范圍" 33 */ 34 if(index<0 || index>arr.length-1){ 35 throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數(shù)組的使用范圍"); 36 } 37 38 int ele = arr[index]; 39 return ele; 40 } 41 } 2.2 Objects非空判斷還記得我們學(xué)習(xí)過一個類Objects嗎,曾經(jīng)提到過它由一些靜態(tài)的實用方法組成,這些方法是null-save(空指針安全的)或null-tolerant(容忍空指針的),那么在它的源碼中,對對象為null的值進(jìn)行了拋出異常操作。 Obects類中的靜態(tài)方法 public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } 代碼示例: 1 public class Demo04Objects { 2 public static void main(String[] args) { 3 method(null); 4 } 5 6 public static void method(Object obj){ 7 //對傳遞過來的參數(shù)進(jìn)行合法性判斷,判斷是否為null 8 /*if(obj == null){ 9 throw new NullPointerException("傳遞的對象的值是null"); 10 }*/ 11 12 //Objects.requireNonNull(obj); 13 Objects.requireNonNull(obj,"傳遞的對象的值是null"); 14 } 15 } 2.3 聲明異常throws 聲明異常:將問題標(biāo)識出來,報告給調(diào)用者。如果方法內(nèi)通過throw拋出了編譯時異常,而沒有捕獲處理(稍后講解該方式),那么必須通過throws進(jìn)行聲明,讓調(diào)用者去處理。 聲明異常格式: 修飾符 返回值類型 方法名(參數(shù)) throws 異常類名1,異常類名2…{ } throws關(guān)鍵字:處理異常的第一種方式,交給別人處理 作用: 當(dāng)方法內(nèi)部拋出異常對象的時候,那么我們就必須處理這個異常對象 可以使用throws關(guān)鍵字處理異常對象,會把異常對象聲明拋出給方法的調(diào)用者處理(自己不處理,給別人處理),最終交給JVM處理 --> 中斷處理 使用格式:在方法聲明時使用 修飾符 返回值類型 方法名(參數(shù)列表) throws AAAException,BBBException...{ throws new AAAException("產(chǎn)生原因"); throws new BBBException("產(chǎn)生原因"); } 注意: 1、throws關(guān)鍵字必須寫在方法聲明處 2、throws關(guān)鍵字后邊聲明的異常必須是Exception或是Exception的子類 3、方法內(nèi)部如果拋出了多個異常對象,那么throws后邊也必須聲明多個異常 4、調(diào)用了一個聲明拋出異常的方法,我們就必須處理聲明的異常 要么繼續(xù)使用throws聲明拋出,交給方法的調(diào)用者處理,最終交給JVM 要么try...catch自己處理異常 代碼示例: 1 public class Demo05Throws { 2 3 /* 4 FileNotFoundException extends IOException extends Exception 5 如果拋出的多個異常對象有子父類關(guān)系,那么直接聲明父類即可 6 */ 7 //public static void main(String[] args) throws FileNotFoundException,IOException { 8 //public static void main(String[] args) throws IOException { 9 public static void main(String[] args) throws Exception { 10 //readFile("c:\\a.txt"); 11 //readFile("d:\\a.txt"); 12 readFile("d:\\a.tx"); 13 } 14 15 /* 16 定義一個方法,對傳遞的文件路徑進(jìn)行合法性判斷 17 如果路徑不是"c:\\a.txt",那么我們就拋出文件找不到異常對象,告知方法的調(diào)用者 18 注意: 19 20 */ 21 22 public static void readFile(String fileName) throws FileNotFoundException,IOException { 23 if (!fileName.equals("c:\\a.txt")){ 24 throw new FileNotFoundException("傳遞的路徑不是c:\\a.txt"); 25 } 26 27 /* 28 如果傳遞的路徑,不是.txt結(jié)尾 29 那么我們就拋出IO異常對象,告知方法的調(diào)用者,文件的后綴名不對 30 */ 31 32 if (!fileName.endsWith(".txt")){ 33 throw new IOException("文件的后綴名不對"); 34 } 35 System.out.printf("路徑?jīng)]有問題,讀取文件"); 36 } 37 } 2.4 捕獲異常try…catch 如果異常出現(xiàn)的話,會立刻終止程序,所以我們得處理異常:
try...catch:異常處理的第二種方式,自己處理異常 } Throwable類中定義了3個異常處理的方法 包含了異常的類型,異常的原因,還包括異常出現(xiàn)的位置,在開發(fā)和調(diào)試階段,都得使用printStackTrace。 代碼示例: 1 public class Demo01TryCatch { 2 public static void main(String[] args) { 3 try{ 4 //可能產(chǎn)生異常的代碼 5 readFile("d:\\a.tx"); 6 System.out.println("資源釋放"); 7 }catch (IOException e){//try中拋出什么異常對象,catch就定義什么異常變量,用來接收這個異常對象 8 //異常的處理邏輯,異常異常對象之后,怎么處理異常對象 9 //System.out.println("catch - 傳遞的文件后綴不是.txt"); 10 11 /* 12 Throwable類中定義了3個異常處理的方法 13 String getMessage() 返回此 throwable 的簡短描述。 14 String toString() 返回此 throwable 的詳細(xì)消息字符串。 15 void printStackTrace() JVM打印異常對象,默認(rèn)此方法,打印的異常信息是最全面的 16 */ 17 //System.out.println(e.getMessage());//文件的后綴名不對 18 //System.out.println(e.toString());//重寫Object類的toString java.io.IOException: 文件的后綴名不對 19 //System.out.println(e);//java.io.IOException: 文件的后綴名不對 20 21 /* 22 java.io.IOException: 文件的后綴名不對 23 at com.itheima.demo02.Exception.Demo01TryCatch.readFile(Demo01TryCatch.java:55) 24 at com.itheima.demo02.Exception.Demo01TryCatch.main(Demo01TryCatch.java:27) 25 */ 26 e.printStackTrace(); 27 } 28 System.out.println("后續(xù)代碼"); 29 } 30 31 /* 32 如果傳遞的路徑,不是.txt結(jié)尾 33 那么我們就拋出IO異常對象,告知方法的調(diào)用者,文件的后綴名不對 34 35 */ 36 public static void readFile(String fileName) throws IOException { 37 38 if(!fileName.endsWith(".txt")){ 39 throw new IOException("文件的后綴名不對"); 40 } 41 42 System.out.println("路徑?jīng)]有問題,讀取文件"); 43 } 44 } 2.4 finally 代碼塊 finally:有一些特定的代碼無論異常是否發(fā)生,都需要執(zhí)行。另外,因為異常會引發(fā)程序跳轉(zhuǎn),導(dǎo)致有些語句執(zhí)行不到。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執(zhí)行的。 finally代碼塊 }finally{ 3.當(dāng)只有在try或者catch中調(diào)用退出JVM的相關(guān)方法,此時finally才不會執(zhí)行,否則finally永遠(yuǎn)會執(zhí)行。 代碼示例: 1 public class Demo02TryCatchFinally { 2 public static void main(String[] args) { 3 try { 4 //可能會產(chǎn)生異常的代碼 5 readFile("c:\\a.tx"); 6 } catch (IOException e) { 7 //異常的處理邏輯 8 e.printStackTrace(); 9 } finally { 10 //無論是否出現(xiàn)異常,都會執(zhí)行 11 System.out.println("資源釋放"); 12 } 13 } 14 15 /* 16 如果傳遞的路徑,不是.txt結(jié)尾 17 那么我們就拋出IO異常對象,告知方法的調(diào)用者,文件的后綴名不對 18 19 */ 20 public static void readFile(String fileName) throws IOException { 21 22 if(!fileName.endsWith(".txt")){ 23 throw new IOException("文件的后綴名不對"); 24 } 25 26 System.out.println("路徑?jīng)]有問題,讀取文件"); 27 } 28 } 2.5 異常注意事項 多個異常使用捕獲又該如何處理呢? 一般我們是使用一次捕獲多次處理方式,格式如下: try{ 編寫可能會出現(xiàn)異常的代碼 }catch(異常類型A e){ 當(dāng)try中出現(xiàn)A類型異常,就用該catch來捕獲. 處理異常的代碼 //記錄日志/打印異常信息/繼續(xù)拋出異常 }catch(異常類型B e){ 當(dāng)try中出現(xiàn)B類型異常,就用該catch來捕獲. 處理異常的代碼 //記錄日志/打印異常信息/繼續(xù)拋出異常 } 注意:這種異常處理方式,要求多個catch中的異常不能相同,并且若catch中的多個異常之間有子父類異常的關(guān)系,那么子類異常要求在上面的catch處理,父類異常在下面的catch處理。
代碼示例: 1 public class Demo01Exception { 2 public static void main(String[] args) { 3 /* 4 多個異常使用捕獲又該如何處理呢? 5 1. 多個異常分別處理。 6 2. 多個異常一次捕獲,多次處理。 7 3. 多個異常一次捕獲一次處理。 8 */ 9 10 //1. 多個異常分別處理。 11 /* try { 12 int[] arr = {1,2,3}; 13 System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 14 }catch (ArrayIndexOutOfBoundsException e){ 15 System.out.println(e); 16 } 17 18 try{ 19 List<Integer> list = List.of(1, 2, 3); 20 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 21 }catch (IndexOutOfBoundsException e){ 22 System.out.println(e); 23 }*/ 24 25 //2. 多個異常一次捕獲,多次處理。 26 /*try { 27 int[] arr = {1,2,3}; 28 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 29 List<Integer> list = List.of(1, 2, 3); 30 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 31 }catch (ArrayIndexOutOfBoundsException e){ 32 System.out.println(e); 33 }catch (IndexOutOfBoundsException e){ 34 System.out.println(e); 35 }*/ 36 37 /* 38 一個try多個catch注意事項: 39 catch里邊定義的異常變量,如果有子父類關(guān)系,那么子類的異常變量必須寫在上邊,否則就會報錯 40 ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException 41 */ 42 /*try { 43 int[] arr = {1,2,3}; 44 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 45 List<Integer> list = List.of(1, 2, 3); 46 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 47 }catch (IndexOutOfBoundsException e){ 48 System.out.println(e); 49 }catch (ArrayIndexOutOfBoundsException e){ 50 System.out.println(e); 51 }*/ 52 53 //3. 多個異常一次捕獲一次處理。 54 /*try { 55 int[] arr = {1,2,3}; 56 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 57 List<Integer> list = List.of(1, 2, 3); 58 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 59 }catch (Exception e){ 60 System.out.println(e); 61 }*/ 62 63 //運(yùn)行時異常被拋出可以不處理。即不捕獲也不聲明拋出。 64 //默認(rèn)給虛擬機(jī)處理,終止程序,什么時候不拋出運(yùn)行時異常了,在來繼續(xù)執(zhí)行程序 65 int[] arr = {1,2,3}; 66 System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 67 List<Integer> list = List.of(1, 2, 3); 68 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 69 70 System.out.println("后續(xù)代碼!"); 71 } 72 } 代碼示例: 1 /* 2 如果finally有return語句,永遠(yuǎn)返回finally中的結(jié)果,避免該情況. 3 */ 4 public class Demo02Exception { 5 public static void main(String[] args) { 6 int a = getA(); 7 System.out.println(a); 8 } 9 10 //定義一個方法,返回變量a的值 11 public static int getA(){ 12 int a = 10; 13 try{ 14 return a; 15 }catch (Exception e){ 16 System.out.println(e); 17 }finally { 18 //一定會執(zhí)行的代碼 19 a = 100; 20 return a; 21 } 22 23 } 24 } 說明:調(diào)用方法后,返回值是100。為了避免永遠(yuǎn)返回finally中的結(jié)果,finally代碼塊中盡量不要使用return語句。 子父類的異常: 代碼示例: 1 /* 2 子父類的異常: 3 - 如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異?;蛘呤歉割惍惓5淖宇惢蛘卟粧伋霎惓!? 4 - 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產(chǎn)生該異常,只能捕獲處理,不能聲明拋出 5 注意: 6 父類異常時什么樣,子類異常就什么樣 7 */ 8 public class Fu { 9 public void show01() throws NullPointerException,ClassCastException{} 10 public void show02() throws IndexOutOfBoundsException{} 11 public void show03() throws IndexOutOfBoundsException{} 12 public void show04() throws Exception {} 13 } 14 15 class Zi extends Fu{ 16 //子類重寫父類方法時,拋出和父類相同的異常 17 public void show01() throws NullPointerException,ClassCastException{} 18 //子類重寫父類方法時,拋出父類異常的子類 19 public void show02() throws ArrayIndexOutOfBoundsException{} 20 //子類重寫父類方法時,不拋出異常 21 public void show03() {} 22 23 /* 24 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。 25 26 */ 27 //public void show04() throws Exception{} 28 29 //此時子類產(chǎn)生該異常,只能捕獲處理,不能聲明拋出 30 public void show04() { 31 try { 32 throw new Exception("編譯期異常"); 33 } catch (Exception e) { 34 e.printStackTrace(); 35 } 36 } 37 } 第三章 自定義異常3.1 概述 為什么需要自定義異常類: 自定義異常類: 代碼示例: 1 /* 2 自定義異常類: 3 java提供的異常類,不夠我們使用,需要自己定義一些異常類 4 格式: 5 public class XXXExcepiton extends Exception | RuntimeException{ 6 添加一個空參數(shù)的構(gòu)造方法 7 添加一個帶異常信息的構(gòu)造方法 8 } 9 注意: 10 1.自定義異常類一般都是以Exception結(jié)尾,說明該類是一個異常類 11 2.自定義異常類,必須的繼承Exception或者RuntimeException 12 繼承Exception:那么自定義的異常類就是一個編譯期異常,如果方法內(nèi)部拋出了編譯期異常,就必須處理這個異常,要么throws,要么try...catch 13 繼承RuntimeException:那么自定義的異常類就是一個運(yùn)行期異常,無需處理,交給虛擬機(jī)處理(中斷處理) 14 */ 15 public class RegisterException extends /*Exception*/ RuntimeException{ 16 //添加一個空參數(shù)的構(gòu)造方法 17 public RegisterException(){ 18 super(); 19 } 20 21 /* 22 添加一個帶異常信息的構(gòu)造方法 23 查看源碼發(fā)現(xiàn),所有的異常類都會有一個帶異常信息的構(gòu)造方法,方法內(nèi)部會調(diào)用父類帶異常信息的構(gòu)造方法,讓父類來處理這個異常信息 24 */ 25 public RegisterException(String message){ 26 super(message); 27 } 28 } 3.2 自定義異常的練習(xí)要求:我們模擬注冊操作,如果用戶名已存在,則拋出異常并提示:親,該用戶名已經(jīng)被注冊。 Demo01RegisterException.java: 1 import java.util.Scanner; 2 3 /* 4 要求:我們模擬注冊操作,如果用戶名已存在,則拋出異常并提示:親,該用戶名已經(jīng)被注冊。 5 6 分析: 7 1.使用數(shù)組保存已經(jīng)注冊過的用戶名(數(shù)據(jù)庫) 8 2.使用Scanner獲取用戶輸入的注冊的用戶名(前端,頁面) 9 3.定義一個方法,對用戶輸入的中注冊的用戶名進(jìn)行判斷 10 遍歷存儲已經(jīng)注冊過用戶名的數(shù)組,獲取每一個用戶名 11 使用獲取到的用戶名和用戶輸入的用戶名比較 12 true: 13 用戶名已經(jīng)存在,拋出RegisterException異常,告知用戶"親,該用戶名已經(jīng)被注冊"; 14 false: 15 繼續(xù)遍歷比較 16 如果循環(huán)結(jié)束了,還沒有找到重復(fù)的用戶名,提示用戶"恭喜您,注冊成功!"; 17 */ 18 public class Demo01RegisterException { 19 // 1.使用數(shù)組保存已經(jīng)注冊過的用戶名(數(shù)據(jù)庫) 20 static String[] usernames = {"張三","李四","王五"}; 21 22 public static void main(String[] args) /*throws RegisterException*/ { 23 //2.使用Scanner獲取用戶輸入的注冊的用戶名(前端,頁面) 24 Scanner sc = new Scanner(System.in); 25 System.out.println("請輸入您要注冊的用戶名:"); 26 String username = sc.next(); 27 checkUsername(username); 28 29 } 30 31 //3.定義一個方法,對用戶輸入的中注冊的用戶名進(jìn)行判斷 32 public static void checkUsername(String username) /*throws RegisterException*/ { 33 //遍歷存儲已經(jīng)注冊過用戶名的數(shù)組,獲取每一個用戶名 34 for (String name : usernames) { 35 //使用獲取到的用戶名和用戶輸入的用戶名比較 36 if(name.equals(username)){ 37 //true:用戶名已經(jīng)存在,拋出RegisterException異常,告知用戶"親,該用戶名已經(jīng)被注冊"; 38 try { 39 throw new RegisterException("親,該用戶名已經(jīng)被注冊"); 40 } catch (RegisterException e) { 41 e.printStackTrace(); 42 return; //結(jié)束方法(否則會執(zhí)行下面的System.out.println("恭喜您,注冊成功!");語句) 43 } 44 } 45 } 46 //如果循環(huán)結(jié)束了,還沒有找到重復(fù)的用戶名,提示用戶"恭喜您,注冊成功!"; 47 System.out.println("恭喜您,注冊成功!"); 48 } 49 } Demo02RegisterException.java: 1 import java.util.Scanner; 2 3 /* 4 要求:我們模擬注冊操作,如果用戶名已存在,則拋出異常并提示:親,該用戶名已經(jīng)被注冊。 5 6 分析: 7 1.使用數(shù)組保存已經(jīng)注冊過的用戶名(數(shù)據(jù)庫) 8 2.使用Scanner獲取用戶輸入的注冊的用戶名(前端,頁面) 9 3.定義一個方法,對用戶輸入的中注冊的用戶名進(jìn)行判斷 10 遍歷存儲已經(jīng)注冊過用戶名的數(shù)組,獲取每一個用戶名 11 使用獲取到的用戶名和用戶輸入的用戶名比較 12 true: 13 用戶名已經(jīng)存在,拋出RegisterException異常,告知用戶"親,該用戶名已經(jīng)被注冊"; 14 false: 15 繼續(xù)遍歷比較 16 如果循環(huán)結(jié)束了,還沒有找到重復(fù)的用戶名,提示用戶"恭喜您,注冊成功!"; 17 */ 18 public class Demo02RegisterException { 19 // 1.使用數(shù)組保存已經(jīng)注冊過的用戶名(數(shù)據(jù)庫) 20 static String[] usernames = {"張三","李四","王五"}; 21 22 public static void main(String[] args) { 23 //2.使用Scanner獲取用戶輸入的注冊的用戶名(前端,頁面) 24 Scanner sc = new Scanner(System.in); 25 System.out.println("請輸入您要注冊的用戶名:"); 26 String username = sc.next(); 27 checkUsername(username); 28 29 } 30 31 //3.定義一個方法,對用戶輸入的中注冊的用戶名進(jìn)行判斷 32 public static void checkUsername(String username) { 33 //遍歷存儲已經(jīng)注冊過用戶名的數(shù)組,獲取每一個用戶名 34 for (String name : usernames) { 35 //使用獲取到的用戶名和用戶輸入的用戶名比較 36 if(name.equals(username)){ 37 //true:用戶名已經(jīng)存在,拋出RegisterException異常,告知用戶"親,該用戶名已經(jīng)被注冊"; 38 throw new RegisterException("親,該用戶名已經(jīng)被注冊");//拋出運(yùn)行期異常,無需處理,交給JVM處理,中斷處理 39 } 40 } 41 42 //如果循環(huán)結(jié)束了,還沒有找到重復(fù)的用戶名,提示用戶"恭喜您,注冊成功!"; 43 System.out.println("恭喜您,注冊成功!"); 44 } 45 } |
|