一盈罐、異常概述與異常體系結(jié)構(gòu)
1.異常:在Java語言中藻三,將程序執(zhí)行中發(fā)生的不正常情況稱為“異忱嬲觯”。 (開發(fā)過程中的語法錯(cuò)誤和邏輯錯(cuò)誤不是異常)
2.?異常體系結(jié)構(gòu)
java.lang.Throwable
|-----java.lang.Error:一般不編寫針對性的代碼進(jìn)行處理昨寞。
|-----java.lang.Exception:可以進(jìn)行異常的處理。
|--------------編譯時(shí)異常(checked)
|-------------------IOException
|--------------------------FileNotFoundException
|-------------------ClassNotFoundException
|--------------運(yùn)行時(shí)異常(unchecked,RuntimeException)
|-------------------NullPointerException空指針異常
|-------------------ArrayIndexOutOfBoundsException數(shù)組角標(biāo)越界
|-------------------ClassCastException類型轉(zhuǎn)換異常
|-------------------NumberFormatException數(shù)值類型異常
|-------------------InputMismatchException輸入不匹配異常
|-------------------ArithmeticException算術(shù)異常
public class ExceptionTest {
? //******************以下是編譯時(shí)異常***************************
? @Test
? public void test7(){
// File file = new File("hello.txt");
// FileInputStream fis = new FileInputStream(file);
//
// int data = fis.read();
// while(data != -1){
// System.out.print((char)data);
// data = fis.read();
// }
//
// fis.close();
? }
? //******************以下是運(yùn)行時(shí)異常***************************
? //ArithmeticException
? @Test
? public void test6(){
? ? int a = 10;
? ? int b = 0;
? ? System.out.println(a / b);
? }
? //InputMismatchException
? @Test
? public void test5(){
? ? Scanner scanner = new Scanner(System.in);
? ? int score = scanner.nextInt();
? ? System.out.println(score);
? ? scanner.close();
? }
? //NumberFormatException
? @Test
? public void test4(){
? ? String str = "123";
? ? str = "abc";
? ? int num = Integer.parseInt(str);
? }
? //ClassCastException
? @Test
? public void test3(){
? ? Object obj = new Date();
? ? String str = (String)obj;
? }
? //IndexOutOfBoundsException
? @Test
? public void test2(){
? ? //ArrayIndexOutOfBoundsException
// int[] arr = new int[10];
// System.out.println(arr[10]);
? ? //StringIndexOutOfBoundsException
? ? String str = "abc";
? ? System.out.println(str.charAt(3));
? }
? //NullPointerException
? @Test
? public void test1(){
// int[] arr = null;
// System.out.println(arr[3]);
? ? String str = "abc";
? ? str = null;
? ? System.out.println(str.charAt(0));
? }
}
Java程序在執(zhí)行過程中所發(fā)生的異常事件可分為兩類:
Error:Java虛擬機(jī)無法解決的嚴(yán)重問題。如:JVM系統(tǒng)內(nèi)部錯(cuò)誤援岩、資源 耗盡等嚴(yán)重情況歼狼。比如:StackOverflowError和OOM。一般不編寫針對性 的代碼進(jìn)行處理享怀。
public class ErrorTest {
? public static void main(String[] args) {
? ? //1.棧溢出:java.lang.StackOverflowError
//? main(args);
? ? //2.堆溢出:java.lang.OutOfMemoryError
? ? Integer[] arr = new Integer[1024*1024*1024];
? }
}
Exception: 其它因編程錯(cuò)誤或偶然的外在因素導(dǎo)致的一般性問題羽峰,可以使 用針對性的代碼進(jìn)行處理。例如: ?空指針訪問 ?試圖讀取不存在的文件 ?網(wǎng)絡(luò)連接中斷 ?數(shù)組角標(biāo)越界凹蜈。
3.對于這些錯(cuò)誤限寞,一般有兩種解決方法:一是遇到錯(cuò)誤就終止程序 的運(yùn)行。另一種方法是由程序員在編寫程序時(shí)仰坦,就考慮到錯(cuò)誤的 檢測履植、錯(cuò)誤消息的提示,以及錯(cuò)誤的處理悄晃。
捕獲錯(cuò)誤最理想的是在編譯期間玫霎,但有的錯(cuò)誤只有在運(yùn)行時(shí)才會發(fā)生。 比如:除數(shù)為0妈橄,數(shù)組下標(biāo)越界等 ? 分類:編譯時(shí)異常和運(yùn)行時(shí)異常
運(yùn)行時(shí)異常
是指編譯器不要求強(qiáng)制處置的異常庶近。一般是指編程時(shí)的邏輯錯(cuò)誤,是程序 員應(yīng)該積極避免其出現(xiàn)的異常眷蚓。java.lang.RuntimeException類及它的子?類都是運(yùn)行時(shí)異常鼻种。
對于這類異常,可以不作處理沙热,因?yàn)檫@類異常很普遍叉钥,若全處理可能會對 程序的可讀性和運(yùn)行效率產(chǎn)生影響。
編譯時(shí)異常
是指編譯器要求必須處置的異常篙贸。即程序在運(yùn)行時(shí)由于外界因素造成的一 般性異常投队。編譯器要求Java程序必須捕獲或聲明所有編譯時(shí)異常。
對于這類異常爵川,如果程序不處理敷鸦,可能會帶來意想不到的結(jié)果。
異常處理機(jī)制
Java采用的異常處理機(jī)制寝贡,是將異常處理的程序代碼集中在一起扒披, 與正常的程序代碼分開,使得程序簡潔圃泡、優(yōu)雅谎碍,并易于維護(hù)。
關(guān)于異常對象的產(chǎn)生:① 系統(tǒng)自動生成的異常對象
異常的處理:抓拋模型
?過程一:"拋":程序在正常執(zhí)行的過程中洞焙,一旦出現(xiàn)異常蟆淀,就會在異常代碼處生成一個(gè)對應(yīng)異常類的對象拯啦。并將此對象拋出。?一旦拋出對象以后熔任,其后的代碼就不再執(zhí)行褒链。
過程二:"抓":可以理解為異常的處理方式:① try-catch-finally ② throws。
方式一:try-catch-finally的使用(Alt+Shift+Z)
try{
? //可能出現(xiàn)異常的代碼
? }catch(異常類型1 變量名1){
//處理異常的方式1
? }catch(異常類型2 變量名2){
//處理異常的方式2
}catch(異常類型3 變量名3){
? //處理異常的方式3
}
? ....
finally{
? //一定會執(zhí)行的代碼
}
1. finally是可選的疑苔。
2. 使用try將可能出現(xiàn)異常代碼包裝起來甫匹,在執(zhí)行過程中,一旦出現(xiàn)異常惦费,就會生成一個(gè)對應(yīng)異常類的對象,根據(jù)此對象的類型薪贫,去catch中進(jìn)行匹配。
3. 一旦try中的異常對象匹配到某一個(gè)catch時(shí)瞧省,就進(jìn)入catch中進(jìn)行異常的處理。一旦處理完成鞍匾,就跳出當(dāng)前的try-catch結(jié)構(gòu)(在沒有寫finally的情況)交洗。繼續(xù)執(zhí)行其后的代碼构拳。
4. catch中的異常類型如果沒有子父類關(guān)系,則誰聲明在上梁棠,誰聲明在下無所謂。catch中的異常類型如果滿足子父類關(guān)系掰茶,則要求子類一定聲明在父類的上面蜜笤。否則,報(bào)錯(cuò)把兔。
5. 常用的異常對象處理的方式: ① String getMessage() ② printStackTrace()
getMessage() 獲取異常信息,返回字符串?printStackTrace() 獲取異常類名和異常信息县好,以及異常出 現(xiàn)在程序中的位置。返回值void缕贡。
printStackTrace() 獲取異常類名和異常信息翁授,以及異常出 現(xiàn)在程序中的位置拣播。返回值void。
6. 在try結(jié)構(gòu)中聲明的變量收擦,再出了try結(jié)構(gòu)以后贮配,就不能再被調(diào)用。7. try-catch-finally結(jié)構(gòu)可以嵌套塞赂。
public class ExceptionTest1 {
? @Test
? public void test2(){
? ? try{
? ? ? File file = new File("hello.txt");
? ? ? FileInputStream fis = new FileInputStream(file);
? ? ? int data = fis.read();
? ? ? while(data != -1){
? ? ? ? System.out.print((char)data);
? ? ? ? data = fis.read();
? ? ? }
? ? ? fis.close();
? ? }catch(FileNotFoundException e){
? ? ? e.printStackTrace();
? ? }catch(IOException e){
? ? ? e.printStackTrace();
? ? }
? }
? @Test
? public void test1(){
? ? String str = "123";
? ? str = "abc";
? ? int num = 0;
? ? try{
? ? ? num = Integer.parseInt(str);
? ? ? System.out.println("hello-----1");
? ? }catch(NumberFormatException e){
// System.out.println("出現(xiàn)數(shù)值轉(zhuǎn)換異常了泪勒,不要著急....");
? ? ? //String getMessage():
// System.out.println(e.getMessage());
? ? ? //printStackTrace():
? ? ? ? e.printStackTrace();
? ? }catch(NullPointerException e){
? ? ? System.out.println("出現(xiàn)空指針異常了,不要著急....");
? ? }catch(Exception e){
? ? ? System.out.println("出現(xiàn)異常了宴猾,不要著急....");
? ? }
? ? System.out.println(num);
? ? System.out.println("hello-----2");
? }
}
try-catch-finally中finally的使用:
1.finally是可選的
2.finally中聲明的是一定會被執(zhí)行的代碼圆存。即使catch中又出現(xiàn)異常了,try中有return語句仇哆,catch中有return語句等情況沦辙。
3.像數(shù)據(jù)庫連接、輸入輸出流税产、網(wǎng)絡(luò)編程Socket等資源怕轿,JVM是不能自動的回收的,我們需要自己手動的進(jìn)行資源的?釋放辟拷。此時(shí)的資源釋放撞羽,就需要聲明在finally中。
public class FinallyTest {
? @Test//3
? public void test2(){
? ? FileInputStream fis = null;
? ? try {
? ? ? File file = new File("hello1.txt");
? ? ? fis = new FileInputStream(file);
? ? ? int data = fis.read();
? ? ? while(data != -1){
? ? ? ? System.out.print((char)data);
? ? ? ? data = fis.read();
? ? ? }
? ? } catch (FileNotFoundException e) {
? ? ? e.printStackTrace();
? ? } catch (IOException e) {
? ? ? e.printStackTrace();
? ? }finally{
? ? ? try {
? ? ? ? if(fis != null)
? ? ? ? ? fis.close();
? ? ? } catch (IOException e) {
? ? ? ? e.printStackTrace();
? ? ? }
? ? }
? }
? @Test//2
? public void testMethod(){
? ? int num = method();
? ? System.out.println(num);
? }
? public int method(){
? ? try{
? ? ? int[] arr = new int[10];
? ? ? System.out.println(arr[10]);
? ? ? return 1;
? ? }catch(ArrayIndexOutOfBoundsException e){
? ? ? e.printStackTrace();
? ? ? return 2;
? ? }finally{
? ? ? System.out.println("我一定會被執(zhí)行");
? ? ? return 3;//3
? ? }
? }
? @Test//1
? public void test1(){
? ? try{
? ? ? int a = 10;
? ? ? int b = 0;
? ? ? System.out.println(a / b);
? ? }catch(ArithmeticException e){
? ? ? e.printStackTrace();
// int[] arr = new int[10];
// System.out.println(arr[10]);
? ? }catch(Exception e){
? ? ? e.printStackTrace();
? ? }
// System.out.println("我好帥吧蓝场>魑伞!隅俘!~~");
? ? finally{
? ? ? System.out.println("我好帥啊~~");
? ? }
? }
}
使用try-catch-finally處理編譯時(shí)異常邻奠,使得程序在編譯時(shí)就不再報(bào)錯(cuò),但是運(yùn)行時(shí)仍可能報(bào)錯(cuò)为居。相當(dāng)于我們使用try-catch-finally將一個(gè)編譯時(shí)可能出現(xiàn)的異常碌宴,延遲到運(yùn)行時(shí)出現(xiàn)。
開發(fā)中蒙畴,由于運(yùn)行時(shí)異常比較常見贰镣,所以我們通常就不針對運(yùn)行時(shí)異常編寫try-catch-finally了。
* 針對于編譯時(shí)異常膳凝,我們說一定要考慮異常的處理碑隆。
方式二:throws + 異常類型
"throws + 異常類型"寫在方法的聲明處。指明此方法執(zhí)行時(shí)蹬音,可能會拋出的異常類型上煤。
一旦當(dāng)方法體執(zhí)行時(shí)著淆,出現(xiàn)異常拴疤,仍會在異常代碼處生成一個(gè)異常類的對象嘉熊,此對象滿足throws后異常類型時(shí),就會被拋出凫佛。異常代碼后續(xù)的代碼孕惜,就不再執(zhí)行!
public class ExceptionTest2 {
? public static void main(String[] args){
? ? try{
? ? ? method2();
? ? }catch(IOException e){
? ? ? e.printStackTrace();
? ? }
// method3();
? }
? public static void method3(){
? ? try {
? ? ? method2();
? ? } catch (IOException e) {
? ? ? e.printStackTrace();
? ? }
? }
? public static void method2() throws IOException{
? ? method1();
? }
? public static void method1() throws FileNotFoundException,IOException{
? ? File file = new File("hello1.txt");
? ? FileInputStream fis = new FileInputStream(file);
? ? int data = fis.read();
? ? while(data != -1){
? ? ? System.out.print((char)data);
? ? ? data = fis.read();
? ? }
? ? fis.close();
? ? System.out.println("hahaha!");
? }
}
② 手動的生成一個(gè)異常對象毫炉,并拋出(throw)
public class StudentTest {
? public static void main(String[] args) {
? ? try {
? ? ? Student s = new Student();
? ? ? s.regist(-1001);
? ? ? System.out.println(s);
? ? } catch (Exception e) {
// e.printStackTrace();
? ? ? System.out.println(e.getMessage());
? ? }
? }
}
class Student{
? private int id;
? public void regist(int id) throws Exception {
? ? if(id > 0){
? ? ? this.id = id;
? ? }else{
// System.out.println("您輸入的數(shù)據(jù)非法削罩!");
? ? ? //手動拋出異常對象
// throw new RuntimeException("您輸入的數(shù)據(jù)非法!");
// throw new Exception("您輸入的數(shù)據(jù)非法进陡!");
? ? ? throw new MyException("不能輸入負(fù)數(shù)");
? ? ? //錯(cuò)誤的
// throw new String("不能輸入負(fù)數(shù)");
? ? }
? }
? @Override
? public String toString() {
? ? return "Student [id=" + id + "]";
? }
}
總結(jié): try-catch-finally:真正的將異常給處理掉了微服。
?throws的方式只是將異常拋給了方法的調(diào)用者。 并沒有真正將異常處理掉糙麦。
?4.開發(fā)中如何選擇使用try-catch-finally 還是使用throws丛肮?
如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws焚廊,意味著如果子類重寫的方法中有異常伴鳖,必須使用try-catch-finally方式處理徙硅。
執(zhí)行的方法a中,先后又調(diào)用了另外的幾個(gè)方法须肆,這幾個(gè)方法是遞進(jìn)關(guān)系執(zhí)行的。我們建議這幾個(gè)方法使用throws的方式進(jìn)行處理豌汇。而執(zhí)行的方法a可以考慮使用try-catch-finally方式進(jìn)行處理。
5.如何自定義異常類宛徊?
(1). 繼承于現(xiàn)有的異常結(jié)構(gòu):RuntimeException 逻澳、Exception(必須顯示處理異常)
(2). 提供全局常量:serialVersionUID
(3). 提供重載的構(gòu)造器
public class MyException extends Exception{
? static final long serialVersionUID = -7034897193246939L;
? public MyException(){
? }
? public MyException(String msg){
? ? super(msg);
? }
}