接口,是Java語言中一種引用類型,是方法的集合。接口的內部主要就是封裝了方法,包含抽象方法(JDK 7及之前),默認方法和靜態方法(JDK 8),私有方法 (JDK 9)。前端
接口定義:java
它與定義類方式類似,可是使用 interface 關鍵字。它也會被編譯成.class文件,但必定要明確它並非類,而是另一種引用數據類型。程序員
引用類型:數組、類、接口數據庫
接口語法:編程
1 public interface 接口名稱 { 2 // 常量 3 // 抽象方法 4 // 默認方法 5 // 靜態方法 6 // 私有方法 7 }
接口當中也能夠定義「成員變量」,可是必須使用public static final三個關鍵字進行修飾。從效果上看,這其實就是接口的【常量】。數組
語法編程語言
1 public static final 數據類型 常量名稱 = 數據值;
備註:一旦使用final關鍵字進行修飾,說明不可改變。ide
注意事項:ui
1. 接口當中的常量,能夠省略public static final,注意:不寫也照樣是這樣。spa
2. 接口當中的常量,必須進行賦值;不能不賦值。
3. 接口中常量的名稱,使用徹底大寫的字母,用下劃線進行分隔。(推薦命名規則)
抽象方法:使用 abstract 關鍵字修飾,能夠省略,沒有方法體。該方法供子類實現使用。
語法:
1 public interface InterFaceName { 2 public abstract void method(); 3 }
默認方法:使用 default 修飾,不可省略,供子類調用或者子類重寫。
語法:
1 public interface InterFaceName { 2 public default void method() { 3 // 執行語句 4 } 5 }
備註:接口當中的默認方法,能夠解決接口升級的問題。及能夠後期進行重寫升級。
靜態方法:使用 static 修飾,供接口直接調用。
1 public interface InterFaceName { 2 public static void method2() { 3 // 執行語句 4 } 5 }
普通私有方法:解決多個默認方法之間重複代碼問題。
格式
1 private 返回值類型 方法名稱(參數列表) { 2 方法體 3 }
1 public interface MyInterfacePrivateA { 2 3 public default void methodDefault1() { 4 System.out.println("默認方法1"); 5 methodCommon(); 6 } 7 8 public default void methodDefault2() { 9 System.out.println("默認方法2"); 10 methodCommon(); 11 } 12 13 // 普通私有方法 14 private void methodCommon() { 15 System.out.println("AAA"); 16 System.out.println("BBB"); 17 System.out.println("CCC"); 18 } 19 20 }
靜態私有方法:解決多個靜態方法之間重複代碼問題
格式
1 private static 返回值類型 方法名稱(參數列表) { 2 方法體 3 }
1 public interface MyInterfacePrivateB { 2 3 public static void methodStatic1() { 4 System.out.println("靜態方法1"); 5 methodStaticCommon(); 6 } 7 8 public static void methodStatic2() { 9 System.out.println("靜態方法2"); 10 methodStaticCommon(); 11 } 12 13 private static void methodStaticCommon() { 14 System.out.println("AAA"); 15 System.out.println("BBB"); 16 System.out.println("CCC"); 17 } 18 19 }
接口使用步驟:
1. 接口不能直接使用,必須有一個「實現類」來「實現」該接口。
格式:
1 public class 實現類名稱 implements 接口名稱 { 2 // ... 3 }
2. 接口的實現類必須覆蓋重寫(實現)接口中全部的抽象方法。實現:去掉abstract關鍵字,加上方法體大括號。
3. 建立實現類的對象,進行使用。
接口中的常量使用只須要:接口名.常量名。不須要建立對象
1 public interface MyInterfaceConst { 2 // 這其實就是一個常量,一旦賦值,不能夠修改 3 public static final int NUM_OF_MY_CLASS = 12; 4 5 } 6 7 8 -------------------------------------------------------------------------------- 9 public static void main(String[] args) { 10 // 訪問接口當中的常量 11 System.out.println(MyInterfaceConst.NUM_OF_MY_CLASS); 12 }
1. 接口的默認方法,能夠經過接口實現類【對象】,直接調用。
2. 接口的默認方法,也能夠被接口實現類進行覆蓋重寫。
1 public interface MyInterfaceDefault { 2 // 默認方法 3 public default void methodDefault() { 4 System.out.println("這是默認方法"); 5 } 6 } 7 8 9 10 ---------------------------------------------------------------- 11 // 在實現類中能夠對默認方法進行覆蓋重寫,也能夠什麼操做都不作 12 // 可是若是想使用默認方法必需要有實現類 13 public class MyInterfaceDefaultA implements MyInterfaceDefault { 14 // 能夠對默認方法覆蓋重寫 15 } 16 17 18 -------------------------------------------------------------------------- 19 public class Demo02Interface { 20 21 public static void main(String[] args) { 22 // 建立了實現類對象 23 MyInterfaceDefaultA a = new MyInterfaceDefaultA(); 24 25 // 調用默認方法,若是實現類當中沒有,會向上找接口 26 a.methodDefault(); // 這是默認方法 27 28 } 29 }
靜態方法的使用:接口名.靜態方法名(參數);
注意:不能經過接口實現類的對象來調用接口當中的靜態方法。
1 public interface MyInterfaceStatic { 2 3 public static void methodStatic() { 4 System.out.println("這是接口的靜態方法!"); 5 } 6 } 7 8 9 10 ------------------------------------------------------------------ 11 // 實現類 12 public class MyInterfaceStaticImpl implements MyInterfaceStatic { 13 14 } 15 16 17 --------------------------------------------------------------------------- 18 /* 19 注意事項:不能經過接口實現類的對象來調用接口當中的靜態方法。 20 正確用法:經過接口名稱,直接調用其中的靜態方法。 21 格式: 22 接口名稱.靜態方法名(參數); 23 */ 24 public class Demo03Interface { 25 26 public static void main(String[] args) { 27 // 建立了實現類對象 28 MyInterfaceStaticImpl impl = new MyInterfaceStaticImpl(); 29 30 // 錯誤寫法! 31 // impl.methodStatic(); 32 33 // 直接經過接口名稱調用靜態方法 34 MyInterfaceStatic.methodStatic(); 35 } 36 }
在實現類中覆蓋重寫抽象方法。而後建立實現類【對象】調用實現的方法。
1 /* 2 注意事項: 3 1. 接口當中的抽象方法,修飾符必須是兩個固定的關鍵字:public abstract 4 2. 這兩個關鍵字修飾符,能夠選擇性地省略。(今天剛學,因此不推薦。) 5 3. 方法的三要素,能夠隨意定義。 6 */ 7 public interface MyInterfaceAbstract { 8 9 // 這是一個抽象方法 10 public abstract void methodAbs1(); 11 12 // 這也是抽象方法 13 abstract void methodAbs2(); 14 15 // 這也是抽象方法 16 public void methodAbs3(); 17 18 // 這也是抽象方法 19 void methodAbs4(); 20 } 21 22 23 ------------------------------------------------------------------------- 24 public class MyInterfaceAbstractImpl implements MyInterfaceAbstract { 25 @Override 26 public void methodAbs1() { 27 System.out.println("這是第一個方法!"); 28 } 29 30 @Override 31 public void methodAbs2() { 32 System.out.println("這是第二個方法!"); 33 } 34 35 @Override 36 public void methodAbs3() { 37 System.out.println("這是第三個方法!"); 38 } 39 40 @Override 41 public void methodAbs4() { 42 System.out.println("這是第四個方法!"); 43 } 44 } 45 46 47 48 ----------------------------------------------------------------- 49 /* 50 注意事項: 51 若是實現類並無覆蓋重寫接口中全部的抽象方法,那麼這個實現類本身就必須是抽象類。 52 */ 53 public class Demo01Interface { 54 55 public static void main(String[] args) { 56 // 錯誤寫法!不能直接new接口對象使用。 57 // MyInterfaceAbstract inter = new MyInterfaceAbstract(); 58 59 // 建立實現類的對象使用 60 MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl(); 61 impl.methodAbs1(); 62 impl.methodAbs2(); 63 } 64 }
注意事項:若是實現類並無覆蓋重寫接口中全部的抽象方法,那麼這個實現類本身就必須是抽象類。
普通私有方法:只有在其接口中的默認方法能夠調用。
私有靜態方法:只有在其接口中的默認方法和靜態方法能夠調用。
若是一個接口中有多個默認方法,而且方法中有重複的內容,那麼能夠抽取出來,封裝到私有方法中,供默認方法去調用。從設計的角度講,私有的方法是對默認方法和靜態方法的輔助
在繼承體系中,一個類只能繼承一個父類。而對於接口而言,一個類是能夠實現多個接口的,這叫作接口的多實現。而且,一個類能繼承一個父類,同時實現多個接口。
語法
1 class 類名 [extends 父類名] implements 接口名1,接口名2,接口名3... { 2 // 重寫接口中抽象方法【必須】 3 // 重寫接口中默認方法【不重名時可選】 4 }
接口中,有多個抽象方法時,實現類必須重寫全部抽象方法。若是抽象方法有重名的,只須要重寫一次。
1 public interface MyInterfaceA { 2 3 public abstract void methodA(); 4 5 public abstract void methodAbs(); 6 7 } 8 9 10 11 ------------------------------------------------------- 12 public interface MyInterfaceB { 13 14 public abstract void methodB(); 15 16 public abstract void methodAbs(); 17 18 } 19 20 21 22 ------------------------------------------------------------ 23 public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { 24 25 @Override 26 public void methodA() { 27 System.out.println("覆蓋重寫了A方法"); 28 } 29 30 31 @Override 32 public void methodB() { 33 System.out.println("覆蓋重寫了B方法"); 34 } 35 36 // 重名的只須要重寫一次 37 @Override 38 public void methodAbs() { 39 System.out.println("覆蓋重寫了AB接口都有的抽象方法"); 40 } 41 }
注意:若是實現類沒有覆蓋重寫全部接口當中的全部抽象方法,那麼實現類就必須是一個抽象類。
接口中,有多個默認方法時,實現類均可繼承使用。不重名的能夠不重寫。若是默認方法有重名的,必須重寫一次。
1 public interface MyInterfaceA { 2 3 public default void methodDefault() { 4 System.out.println("默認方法AAA"); 5 } 6 } 7 8 9 10 --------------------------------------------------- 11 public interface MyInterfaceB { 12 13 public default void methodDefault() { 14 System.out.println("默認方法BBB"); 15 } 16 17 } 18 19 20 21 ------------------------------------------------------- 22 public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { 23 // 兩個接口中重名。必須重寫 24 @Override 25 public void methodDefault() { 26 System.out.println("對多個接口當中衝突的默認方法進行了覆蓋重寫"); 27 } 28 }
接口中,存在同名的靜態方法並不會衝突,緣由是只能經過各自接口名訪問靜態方法。
一個類若是直接父類當中的方法,和接口當中的默認方法產生了衝突,優先用父類當中的方法。
一個接口能繼承另外一個或者多個接口,這和類之間的繼承比較類似。接口的繼承使用 extends 關鍵字,子接口繼承父接口的方法。
1 // 接口A 2 public interface MyInterfaceA { 3 4 public abstract void methodA(); 5 6 public abstract void methodCommon(); 7 8 public default void methodDefault() { 9 System.out.println("AAA"); 10 } 11 } 12 13 14 15 ---------------------------------------------------------- 16 // 接口B 17 public interface MyInterfaceB { 18 19 public abstract void methodB(); 20 21 public abstract void methodCommon(); 22 23 public default void methodDefault() { 24 System.out.println("BBB"); 25 } 26 } 27 28 29 30 -------------------------------------------------------------- 31 // 繼承接口A和B的接口 32 /* 33 這個子接口當中有幾個方法?答:4個。 34 methodA 來源於接口A 35 methodB 來源於接口B 36 methodCommon 同時來源於接口A和B 37 method 來源於我本身 38 */ 39 public interface MyInterface extends MyInterfaceA, MyInterfaceB { 40 41 public abstract void method(); 42 43 @Override 44 public default void methodDefault() { 45 46 } 47 } 48 49 50 ---------------------------------------------------------------------- 51 // 實現類 52 53 public class MyInterfaceImpl implements MyInterface { 54 @Override 55 public void method() { 56 57 } 58 59 @Override 60 public void methodA() { 61 62 } 63 64 @Override 65 public void methodB() { 66 67 } 68 69 @Override 70 public void methodCommon() { 71 72 } 73 }
注意事項:
1. 多個父接口當中的抽象方法若是重複,不要緊。
2. 多個父接口當中的默認方法若是重複,那麼子接口必須進行默認方法的覆蓋重寫,【並且帶着default關鍵字】。
在Java等面向對象的編程語言中,異常自己是一個類,產生異常就是建立異常對象並拋出了一個異常對象。Java處理異常的方式是中斷處理。
注意:異常指的並非語法錯誤,語法錯了,編譯不經過,不會產生字節碼文件,根本不能運行.
Exception
Throwable中的經常使用方法:
public void printStackTrace():打印異常的詳細信息。
包含了異常的類型,異常的緣由,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace。*
public String getMessage():獲取發生異常的緣由。
提示給用戶的時候,就提示錯誤緣由。
public String toString():獲取異常的類型和異常描述信息(不用)。
2,須要將這個異常對象告知給調用者。怎麼告知呢?怎麼將這個異常對象傳遞到調用者處呢?經過關鍵字throw就能夠完成。throw 異常對象。
1 throw new 異常類名(參數); 2 示例: 3 throw new NullPointerException("要訪問的arr數組不存在"); 4 5 throw new ArrayIndexOutOfBoundsException("該索引在數組中不存在,已超出範圍");
注意:
1.throw關鍵字必須寫在方法的內部
2.throw關鍵字後邊new的對象必須是Exception或者Exception的子類對象
3.throw關鍵字拋出指定的異常對象,咱們就必須處理這個異常對象
throw關鍵字後邊建立的是RuntimeException或者是 RuntimeException的子類對象,咱們能夠不處理,默認交給JVM處理(打印異常對象並中斷程序)
throw關鍵字後邊建立的是編譯異常(寫代碼的時候報錯),咱們就必須處理這個異常,要麼throws,要麼try...catch
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 定義一個方法,獲取數組指定索引處的元素 10 參數: 11 int[] arr 12 int index 13 之後(工做中)咱們首先必須對方法傳遞過來的參數進行合法性校驗 14 若是參數不合法,那麼咱們就必須使用拋出異常的方式,告知方法的調用者,傳遞的參數有問題 15 注意: 16 NullPointerException是一個運行期異常,咱們不用處理,默認交給JVM處理 17 ArrayIndexOutOfBoundsException是一個運行期異常,咱們不用處理,默認交給JVM處理 18 */ 19 public static int getElement(int[] arr,int index){ 20 /* 21 咱們能夠對傳遞過來的參數數組,進行合法性校驗 22 若是數組arr的值是null 23 那麼咱們就拋出空指針異常,告知方法的調用者"傳遞的數組的值是null" 24 */ 25 if(arr == null){ 26 throw new NullPointerException("傳遞的數組的值是null"); 27 } 28 29 /* 30 咱們能夠對傳遞過來的參數index進行合法性校驗 31 若是index的範圍不在數組的索引範圍內 32 那麼咱們就拋出數組索引越界異常,告知方法的調用者"傳遞的索引超出了數組的使用範圍" 33 */ 34 if(index<0 || index>arr.length-1){ 35 throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數組的使用範圍"); 36 } 37 38 int ele = arr[index]; 39 return ele; 40 } 41 }
源碼中對throw的使用示例:Object中的方法查看引用對象是否爲null
1 //Obects類中的靜態方法 2 //public static <T> T requireNonNull(T obj):查看指定引用對象不是null。 3 源碼: 4 public static <T> T requireNonNull(T obj) { 5 if (obj == null){ 6 throw new NullPointerException(); 7 } 8 return obj; 9 }
1 import java.util.Objects; 2 3 public class Demo04Objects { 4 public static void main(String[] args) { 5 method(null); 6 } 7 8 public static void method(Object obj){ 9 //對傳遞過來的參數進行合法性判斷,判斷是否爲null 10 // if(obj == null){ 11 // throw new NullPointerException("傳遞的對象的值是null"); 12 // } 13 14 //Objects.requireNonNull(obj); 15 Objects.requireNonNull(obj,"傳遞的對象的值是null"); 16 } 17 }
throws關鍵字:異常處理的第一種方式,交給別人處理
做用:
當方法內部拋出異常對象的時候,那麼咱們就必須處理這個異常對象
可使用throws關鍵字處理異常對象,會把異常對象聲明拋出給方法的調用者處理(本身不處理,給別人處理),最終交給JVM處理-->中斷處理
使用格式:(方法聲明的時候使用)
1 修飾符 返回值類型 方法名(參數列表) throws AAAExcepiton,BBBExcepiton...{ 2 throw new AAAExcepiton("產生緣由"); 3 throw new BBBExcepiton("產生緣由"); 4 ... 5 }
注意:
1.throws關鍵字必須寫在方法聲明處
2.throws關鍵字後邊聲明的異常必須是Exception或者是Exception的子類
3.方法內部若是拋出了多個異常對象,那麼throws後邊必須也聲明多個異常
若是拋出的多個異常對象有子父類關係,那麼直接聲明父類異常便可
4.調用了一個聲明拋出異常的方法,咱們就必須的處理聲明的異常
1)要麼繼續使用throws聲明拋出,交給方法的調用者處理,最終交給JVM
2)要麼try...catch本身處理異常
1 import java.io.FileNotFoundException; 2 import java.io.IOException; 3 4 public class Demo05Throws { 5 /* 6 FileNotFoundException extends IOException extends Excepiton 7 若是拋出的多個異常對象有子父類關係,那麼直接聲明父類異常便可 8 */ 9 //public static void main(String[] args) throws FileNotFoundException,IOException { 10 //public static void main(String[] args) throws IOException { 11 public static void main(String[] args) throws Exception { 12 readFile("c:\\a.tx"); 13 14 System.out.println("後續代碼"); 15 } 16 17 /* 18 定義一個方法,對傳遞的文件路徑進行合法性判斷 19 若是路徑不是"c:\\a.txt",那麼咱們就拋出文件找不到異常對象,告知方法的調用者 20 注意: 21 FileNotFoundException是編譯異常,拋出了編譯異常,就必須處理這個異常 22 可使用throws繼續聲明拋出FileNotFoundException這個異常對象,讓方法的調用者處理 23 */ 24 public static void readFile(String fileName) throws FileNotFoundException,IOException{ 25 if(!fileName.equals("c:\\a.txt")){ 26 throw new FileNotFoundException("傳遞的文件路徑不是c:\\a.txt"); 27 } 28 29 /* 30 若是傳遞的路徑,不是.txt結尾 31 那麼咱們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對 32 */ 33 if(!fileName.endsWith(".txt")){ 34 throw new IOException("文件的後綴名不對"); 35 } 36 37 System.out.println("路徑沒有問題,讀取文件"); 38 } 39 }
try...catch:異常處理的第二種方式,本身處理異常
格式:
1 try{ 2 可能產生異常的代碼 3 }catch(定義一個異常的變量,用來接收try中拋出的異常對象){ 4 異常的處理邏輯,異常異常對象以後,怎麼處理異常對象 5 通常在工做中,會把異常的信息記錄到一個日誌中 6 } 7 ... 8 catch(異常類名 變量名){ 9 10 }
注意:
1.try中可能會拋出多個異常對象,那麼就可使用多個catch來處理這些異常對象
2.若是try中產生了異常,那麼就會執行catch中的異常處理邏輯,執行完畢catch中的處理邏輯,繼續執行try...catch以後的代碼
若是try中沒有產生異常,那麼就不會執行catch中異常的處理邏輯,執行完try中的代碼,繼續執行try...catch以後的代碼
打印錯誤信息的經常使用方法:
public void printStackTrace():打印異常的詳細信息。
包含了異常的類型,異常的緣由,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace。*
public String getMessage():獲取發生異常的緣由。
提示給用戶的時候,就提示錯誤緣由。
public String toString():獲取異常的類型和異常描述信息(不用)。
1 import java.io.IOException; 2 3 public class Demo01TryCatch { 4 public static void main(String[] args) { 5 try{ 6 //可能產生異常的代碼 7 readFile("d:\\a.tx"); 8 System.out.println("資源釋放"); 9 }catch (IOException e){//try中拋出什麼異常對象,catch就定義什麼異常變量,用來接收這個異常對象 10 //異常的處理邏輯,異常異常對象以後,怎麼處理異常對象 11 //System.out.println("catch - 傳遞的文件後綴不是.txt"); 12 13 /* 14 Throwable類中定義了3個異常處理的方法 15 String getMessage() 返回此 throwable 的簡短描述。 16 String toString() 返回此 throwable 的詳細消息字符串。 17 void printStackTrace() JVM打印異常對象,默認此方法,打印的異常信息是最全面的 18 */ 19 //System.out.println(e.getMessage());//文件的後綴名不對 20 //System.out.println(e.toString());//重寫Object類的toString java.io.IOException: 文件的後綴名不對 21 //System.out.println(e);//java.io.IOException: 文件的後綴名不對 22 23 24 // e.printStackTrace(); 25 /* 26 java.io.IOException: 文件的後綴名不對 27 at com.itheima.demo02.Exception.Demo01TryCatch.readFile(Demo01TryCatch.java:55) 28 at com.itheima.demo02.Exception.Demo01TryCatch.main(Demo01TryCatch.java:27) 29 */ 30 31 } 32 System.out.println("後續代碼"); 33 } 34 35 /* 36 若是傳遞的路徑,不是.txt結尾 37 那麼咱們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對 38 */ 39 public static void readFile(String fileName) throws IOException { 40 41 if(!fileName.endsWith(".txt")){ 42 throw new IOException("文件的後綴名不對"); 43 } 44 45 System.out.println("路徑沒有問題,讀取文件"); 46 } 47 } 48 49
格式:
1 try{ 2 可能產生異常的代碼 3 }catch(定義一個異常的變量,用來接收try中拋出的異常對象){ 4 異常的處理邏輯,異常異常對象以後,怎麼處理異常對象 5 通常在工做中,會把異常的信息記錄到一個日誌中 6 } 7 ... 8 catch(異常類名 變量名){ 9 10 }finally{ 11 不管是否出現異常都會執行 12 }
注意:
1,finally不能單獨使用,必須和try一塊兒使用
2,finally通常用於資源釋放(資源回收),不管程序是否出現異常,最後都要資源釋放(IO)
3,當只有在try或者catch中調用退出JVM的相關方法,此時finally纔不會執行,不然finally永遠會執行
1 import java.io.IOException; 2 3 public class Demo02TryCatchFinally { 4 public static void main(String[] args) { 5 try { 6 //可能會產生異常的代碼 7 readFile("c:\\a.tx"); 8 } catch (IOException e) { 9 //異常的處理邏輯 10 e.printStackTrace(); 11 } finally { 12 //不管是否出現異常,都會執行 13 System.out.println("資源釋放"); 14 } 15 } 16 17 /* 18 若是傳遞的路徑,不是.txt結尾 19 那麼咱們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對 20 21 */ 22 public static void readFile(String fileName) throws IOException { 23 24 if(!fileName.endsWith(".txt")){ 25 throw new IOException("文件的後綴名不對"); 26 } 27 28 System.out.println("路徑沒有問題,讀取文件"); 29 } 30 }
注意1:多個異常使用捕獲又該如何處理呢?
1. 多個異常分別處理。
2. 多個異常一次捕獲,屢次處理。【推薦】
3. 多個異常一次捕獲一次處理。
1 import java.util.List; 2 3 public class Demo01Exception { 4 public static void main(String[] args) { 5 /* 6 多個異常使用捕獲又該如何處理呢? 7 1. 多個異常分別處理。 8 2. 多個異常一次捕獲,屢次處理。 9 3. 多個異常一次捕獲一次處理。 10 */ 11 12 //1. 多個異常分別處理。 13 try { 14 int[] arr = {1,2,3}; 15 System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 16 }catch (ArrayIndexOutOfBoundsException e){ 17 System.out.println(e); 18 } 19 20 try{ 21 List<Integer> list = List.of(1, 2, 3); 22 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 23 }catch (IndexOutOfBoundsException e){ 24 System.out.println(e); 25 } 26 27 28 //2. 多個異常一次捕獲,屢次處理。 29 try { 30 int[] arr = {1,2,3}; 31 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 32 List<Integer> list = List.of(1, 2, 3); 33 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 34 }catch (ArrayIndexOutOfBoundsException e){ 35 System.out.println(e); 36 }catch (IndexOutOfBoundsException e){ 37 System.out.println(e); 38 } 39 40 /* 41 一個try多個catch注意事項: 42 catch裏邊定義的異常變量,若是有子父類關係,那麼子類的異常變量必須寫在上邊,不然就會報錯 43 ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException 44 */ 45 try { 46 int[] arr = {1,2,3}; 47 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 48 List<Integer> list = List.of(1, 2, 3); 49 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 50 }catch (IndexOutOfBoundsException e){ 51 System.out.println(e); 52 }catch (ArrayIndexOutOfBoundsException e){ 53 System.out.println(e); 54 } 55 56 //3. 多個異常一次捕獲一次處理。 57 try { 58 int[] arr = {1,2,3}; 59 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 60 List<Integer> list = List.of(1, 2, 3); 61 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 62 }catch (Exception e){ 63 System.out.println(e); 64 } 65 } 66 }
注意2:運行時異常被拋出能夠不處理。即不捕獲也不聲明拋出。
默認給虛擬機處理,終止程序,何時不拋出運行時異常了,在來繼續執行程序
1 import java.util.List; 2 3 public class Demo01Exception { 4 public static void main(String[] args) { 5 6 //運行時異常被拋出能夠不處理。即不捕獲也不聲明拋出。 7 //默認給虛擬機處理,終止程序,何時不拋出運行時異常了,在來繼續執行程序 8 int[] arr = {1,2,3}; 9 System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 10 List<Integer> list = List.of(1, 2, 3); 11 System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3 12 13 System.out.println("後續代碼!"); 14 } 15 }
注意3:若是finally有return語句,永遠返回finally中的結果,避免該狀況.
1 public class Demo02Exception { 2 public static void main(String[] args) { 3 int a = getA(); 4 System.out.println(a);// 100 5 } 6 7 //定義一個方法,返回變量a的值 8 public static int getA(){ 9 int a = 10; 10 try{ 11 return a; 12 }catch (Exception e){ 13 System.out.println(e); 14 }finally { 15 //必定會執行的代碼 16 a = 100; 17 return a; 18 } 19 } 20 }
注意4:子父類的異常:
若是父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。
父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出
1 public class Fu { 2 public void show01() throws NullPointerException,ClassCastException{} 3 public void show02() throws IndexOutOfBoundsException{} 4 public void show03() throws IndexOutOfBoundsException{} 5 public void show04() throws Exception {} 6 } 7 8 class Zi extends Fu{ 9 //子類重寫父類方法時,拋出和父類相同的異常 10 public void show01() throws NullPointerException,ClassCastException{} 11 12 //子類重寫父類方法時,拋出父類異常的子類 13 public void show02() throws ArrayIndexOutOfBoundsException{} 14 15 //子類重寫父類方法時,不拋出異常 16 public void show03() {} 17 18 /* 19 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。 20 */ 21 //public void show04() throws Exception{} 22 23 //此時子類產生該異常,只能捕獲處理,不能聲明拋出 24 public void show04() { 25 try { 26 throw new Exception("編譯期異常"); 27 } catch (Exception e) { 28 e.printStackTrace(); 29 } 30 } 31 }
爲何要自定義異常:
咱們說了Java中不一樣的異常類,分別表示着某一種具體的異常狀況,那麼在開發中老是有些異常狀況是SUN沒有定義好的,此時咱們根據本身業務的異常狀況來定義異常類。例如年齡負數問題,考試成績負數問題等等。
在開發中根據本身業務的異常狀況來定義異常類.
自定義一個業務邏輯異常: RegisterException。一個註冊異常類。
自定義一個編譯期異常: 自定義類 並繼承於java.lang.Exception
。
自定義一個運行時期的異常類:自定義類 並繼承於java.lang.RuntimeException
。
語法:
1 public class XXXExcepiton extends Exception | RuntimeException{ 2 添加一個空參數的構造方法 3 添加一個帶異常信息的構造方法 4 }
注意:
1.自定義異常類通常都是以Exception結尾,說明該類是一個異常類
2.自定義異常類,必須的繼承Exception或者RuntimeException
繼承Exception:那麼自定義的異常類就是一個編譯期異常,若是方法內部拋出了編譯期異常,就必須處理這個異常,要麼throws,要麼try...catch
繼承RuntimeException:那麼自定義的異常類就是一個運行期異常,無需處理,交給虛擬機處理(中斷處理)
1 public class RegisterException extends /*Exception*/ RuntimeException{ 2 //添加一個空參數的構造方法 3 public RegisterException(){ 4 super(); 5 } 6 7 /* 8 添加一個帶異常信息的構造方法 9 查看源碼發現,全部的異常類都會有一個帶異常信息的構造方法,方法內部會調用父類帶異常信息的構造方法,讓父類來處理這個異常信息 10 */ 11 public RegisterException(String message){ 12 super(message); 13 } 14 }
自定義異常的使用語法和系統提供的使用語法相同:
1 public class RegisterException extends /*Exception*/ RuntimeException{ 2 //添加一個空參數的構造方法 3 public RegisterException(){ 4 super(); 5 } 6 7 /* 8 添加一個帶異常信息的構造方法 9 查看源碼發現,全部的異常類都會有一個帶異常信息的構造方法,方法內部會調用父類帶異常信息的構造方法,讓父類來處理這個異常信息 10 */ 11 public RegisterException(String message){ 12 super(message); 13 } 14 } 15 16 17 ======================================== 18 import java.util.Scanner; 19 20 /* 21 要求:咱們模擬註冊操做,若是用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。 22 23 分析: 24 1.使用數組保存已經註冊過的用戶名(數據庫) 25 2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面) 26 3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷 27 遍歷存儲已經註冊過用戶名的數組,獲取每個用戶名 28 使用獲取到的用戶名和用戶輸入的用戶名比較 29 true: 30 用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊"; 31 false: 32 繼續遍歷比較 33 若是循環結束了,尚未找到重複的用戶名,提示用戶"恭喜您,註冊成功!"; 34 */ 35 public class Demo01RegisterException { 36 // 1.使用數組保存已經註冊過的用戶名(數據庫) 37 static String[] usernames = {"張三","李四","王五"}; 38 39 public static void main(String[] args) /*throws RegisterException*/ { 40 //2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面) 41 Scanner sc = new Scanner(System.in); 42 System.out.println("請輸入您要註冊的用戶名:"); 43 String username = sc.next(); 44 checkUsername(username); 45 46 } 47 48 //3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷 49 public static void checkUsername(String username) /*throws RegisterException*/ { 50 //遍歷存儲已經註冊過用戶名的數組,獲取每個用戶名 51 for (String name : usernames) { 52 //使用獲取到的用戶名和用戶輸入的用戶名比較 53 if(name.equals(username)){ 54 //true:用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊"; 55 try { 56 throw new RegisterException("親,該用戶名已經被註冊"); 57 } catch (RegisterException e) { 58 e.printStackTrace(); 59 return; //結束方法 60 } 61 } 62 } 63 //若是循環結束了,尚未找到重複的用戶名,提示用戶"恭喜您,註冊成功!"; 64 System.out.println("恭喜您,註冊成功!"); 65 } 66 }
------------------------------