異常的概述
- 異常概述
- 異常就是Java程序在運行過程中出現的錯誤。
- 由來
- 問題也是現實生活中一個具體事務,也可以通過java 的類的形式進行描述,并封裝成對象。
- 其實就是Java對不正常情況進行描述后的對象體現。
異常的分類圖解
從上面的圖我們可以看到:程序的異常Throwable分為兩類
- 程序的異常:Throwable
- 嚴重問題:Error 我們不處理。這種問題一般都是很嚴重的,比如說內存溢出。
- 問題:Exception
- 編譯期問題:不是RuntimeException的異常 必須進行處理的,因為你不處理,編譯就不能通過。
- 運行期問題:RuntimeException 這種問題我們也不處理,因為是你的問題,而且這個問題出現肯定是我們的代碼不夠嚴謹,需要修正代碼的。
如果程序出現了問題,我們沒有做任何處理,最終jvm會做出默認的處理。
把異常的名稱,原因及出現的問題等信息輸出在控制臺。
我們運行程序,可以看到異常出現了。它為什么會出現異常呢?
- JVM的默認處理方案
- 把異常的名稱,錯誤原因及異常出現的位置等信息輸出在了控制臺
- 程序停止執行
我們在來理解一下JVM的默認處理方案
jvm發現運算是已經違反了數學運算規則,java將這種常見的問題進行描述,并封裝成了對象叫做ArithmeticException
當除0運算發生后,jvm將該問題打包成了一個異常對象.
并將對象拋給調用者main函數,new ArithmeticException(“/by zero”);
main函數收到這個問題時,有兩種處理方式:
- 1. 自己將該問題處理,然后繼續運行
- 2.自己沒有針對的處理方式,只有交給調用main的jvm來處理
jvm有一個默認的異常處理機制,就將該異常進行處理.并將該異常的名稱,異常的信息.異常出現的位置打印在了控制臺上
同時將程序停止運行
Try…Catch
那么我們自己如何處理異常呢?
- 異常的處理方案
- try…catch…finally
- throws
**try...catch...finally的處理格式: **
try {
可能出現問題的代碼;
} catch(異常名 變量) {
針對問題的處理;
} finally {
釋放資源;
}
變形格式:
try {
可能出現問題的代碼;
} catch(異常名 變量) {
針對問題的處理;
}
注意:
try里面的代碼越少越好
catch里面必須有內容,哪怕是給出一個簡單的提示
多異常處理
上面我們處理了一個簡單的異常,如果我們遇到一個復雜的程序需要我們處理多個異常要怎么辦呢?下面我們來學習
- 多異常的處理
- 每一個寫一個try…catch(這樣有點過于麻煩)
- 寫一個try,多個catch
try{
...
}catch(異常類名 變量名) {
...
} catch(異常類名 變量名) {
...
}
...
注意事項: 1:能明確的盡量明確,不要用大的來處理。 2:平級關系的異常誰前誰后無所謂,如果出現了子父關系,父必須在后面。
Throwable中的方法
getMessage():獲取異常信息,返回字符串。
toString():獲取異常類名和異常信息,返回字符串。
printStackTrace():獲取異常類名和異常信息,以及異常出現在程序中的位置。返回值void。
printStackTrace(PrintStream s):通常用該方法將異常內容保存在日志文件中,以便查閱。
異常聲明Throws
有些時候,我們是可以對異常進行處理的,但是又有些時候,我們根本就沒有權限去處理某個異常?;蛘哒f,我處理不了,我就不處理了。
為了解決出錯問題,Java針對這種情況,就提供了另一種處理方案:拋出。
- 格式:
- throws 異常類名
- 注意:這個格式必須跟在方法的括號后面。
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("今天天氣很好");
try {
method();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("但是我要在家學習");
method2();
}
// 編譯期異常的拋出,編譯不通過,我們就要拋出異常了
public static void method() throws ParseException {
String s = "2016-09-03";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);
System.out.println(d);
}
// 運行期異常的拋出
public static void method2() throws ArithmeticException {
int a = 10;
int b = 0;
System.out.println(a / b);
}
}
注意:
- 編譯期異常拋出,將來調用者必須處理。
- 運行期異常拋出,將來調用可以不用處理。
throw
上面講了throws,那么throw又是什么鬼,怎么用,他們有什么區別呢,讓我們帶著疑問出發
概念:
throw:在功能方法內部出現某種情況,程序不能繼續運行,需要進行跳轉時,就用throw把異常對象拋出。如果出現了異常情況,我們可以把該異常拋出,這個時候的拋出的應該是異常的對象。-
throws和throw的區別
- throws
- 用在方法聲明后面,跟的是異常類名
- 可以跟多個異常類名,用逗號隔開
- 表示拋出異常,由該方法的調用者來處理
- throws表示出現異常的一種可能性,并不一定會發生這些異常
- throw
- 用在方法體內,跟的是異常對象名
- 只能拋出一個異常對象名
- 表示拋出異常,由方法體內的語句處理
- throw則是拋出了異常,執行throw則一定拋出了某種異常
- throws
學了這么多異常的處理,那么我們到底該如何處理異常呢?我們來總結一下
- 原則:如果該功能內部可以將問題處理,用try,如果處理不了,交由調用者處理,這是用throws
- 區別:
- 后續程序需要繼續運行就try
- 后續程序不需要繼續運行就throws
finally
- finally的特點
- 被finally控制的語句體一定會執行
- 特殊情況:在執行到finally之前jvm退出了(比如System.exit(0))
- finally的作用
- 用于釋放資源,在IO流操作和數據庫操作中會見到(我們后面學習中會看到)
finally的用法很簡單,這里就不舉例了,我們看一個關于finally典型的題
final,finally和finalize的區別?
final
最終的意思,可以修飾類,成員變量,成員方法
修飾類,類不能被繼承
修飾變量,變量是常量
修飾方法,方法不能被重寫
finally
是異常處理的一部分,用于釋放資源。
一般來說,代碼肯定會執行,特殊情況:在執行到finally之前jvm退出了
finalize
是Object類的一個方法,用于垃圾回收
自定義異常
java不可能對所有的情況都考慮到,所以,在實際的開發中,我們可能需要自己定義異常。而我們自己隨意的寫一個類,是不能作為異常類來看的,要想你的類是一個異常類,就必須繼承自Exception或者RuntimeException
/* * 自定義異常測試類 */
public class StudentDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入學生成績:");
int score = sc.nextInt();
Teacher t = new Teacher();
try {
t.check(score);
} catch (MyException e) {
e.printStackTrace();
}
}
}
/* *自定義 */
class MyException extends Exception {
public MyException() { }
public MyException(String message) {
super(message);
}
}
//老師類
class Teacher {
public void check(int score) throws MyException {
if (score > 100 || score < 0) {
throw new MyException("分數必須在0-100之間");
} else {
System.out.println("分數沒有問題");
}
}
異常注意事項
我們來學習最后一個知識點
- 子類重寫父類方法時,子類的方法必須拋出相同的異常或父類異常的子類。
- 如果父類拋出了多個異常,子類重寫父類時,只能拋出相同的異?;蛘呤撬淖蛹?子類不能拋出父類沒有的異常
- 如果被重寫的方法沒有異常拋出,那么子類的方法絕對不可以拋出異常,如果子類方法內有異常發生,那么子類只能try,不能throws