一、異常的產(chǎn)生
先看下面的這個(gè)demo:
/*
* 異常的產(chǎn)生
*/
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println(0/0);
System.out.println("hello world");
}
}
此時(shí)程序就產(chǎn)生 的異常如下:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at exceptions.ExceptionDemo.main(ExceptionDemo.java:11)
分析:
- JVM檢測(cè)到了問題(0是除數(shù)的問題),于是程序發(fā)生了異常
- JVM就把這個(gè)異常進(jìn)行了對(duì)象的封裝
new ArithmeticException()
- 異常對(duì)象被拋給調(diào)用者main中,main方法接收到這個(gè)異常后萧锉,由于程序中沒有對(duì)異常進(jìn)行處理的方法,因此mian方法也不能處理此異常,于是異常又被拋出到JVM中
- JVM接受到異常后茴丰,采取了默認(rèn)的處理措施,停止運(yùn)行程序天吓,于是后面的這個(gè)syso語句沒有執(zhí)行贿肩。
異常也是對(duì)象,上述例子中異常對(duì)象的描述類是ArithmeticException龄寞,它是用來描述數(shù)學(xué)中算數(shù)問題的 異常類汰规。比如還有常見的空指針異常描述類NullPointerException。
二物邑、異常的繼承體系
Throwable類是所有異常和錯(cuò)誤的父類
Error 錯(cuò)誤
-
Exception 異常
錯(cuò)誤:程序出現(xiàn)了嚴(yán)重的問題溜哮,不修改代碼,根本不能運(yùn)行拂封,人得了非典茬射,艾滋,癌
異常:程序出現(xiàn)了比較輕的問題冒签,處理掉之后在抛,繼續(xù)運(yùn)行,人得了闌尾炎萧恕,感冒
Exception類是所有異常的父類
- 非RuntimeException
- RuntimeException
Throwable中的方法:
- String toString()重寫Object類的方法刚梭,異常信息的詳細(xì)描述?
- String getMessage() 返回異常信息的簡短描述
- void printStackTrace() 異常信息輸出到控制臺(tái)
三肠阱、異常的兩種處理方式
-
直接處理掉異常
demo:
try{ 嘗試捕獲異常的代碼 }catch(異常類 異常變量){ 異常處理代碼 }
-
第二種處理方式就是拋出異常
- throw 手動(dòng)拋出異常,后面寫的是new異常的對(duì)象朴读,寫在方法中
- throws 方法聲明拋出異常屹徘,后面寫的是異常類,寫在方法的聲明上
demo:
/* 異常第二種處理方式衅金,拋出異常 throw throws的用法 ExceptionDemo2.java:21: 錯(cuò)誤: 未報(bào)告的異常錯(cuò)誤Exception; 必須對(duì)其進(jìn)行捕獲或聲明 以便拋出 throw new Exception(); 方法中噪伊,有異常拋出,但是沒有處理過氮唯,因此編譯失敗 異常的編譯提示鉴吹,是Java編譯時(shí)的最后提示 */ class ExceptionDemo2 { public static void main(String[] args) throws Exception { //System.out.println("Hello World!"); //main中調(diào)用了method方法,方法拋出了異常 //main有2個(gè)選擇方法惩琉,一個(gè)是try...catch //另外一個(gè)是豆励,異常我也不處理,交給我的調(diào)用者處理 method(-5); } /* 如果方法的參數(shù)小于0 程序出現(xiàn)異常瞒渠,如果參數(shù)大于0 良蒸,程序是正常的 方法自己,不想處理這個(gè)異常伍玖,把異常交給調(diào)用者處理 在方法聲明上嫩痰,拋出異常,聲明出來有異常私沮,交給調(diào)用者 throws 異常類 */ public static void method(int x)throws Exception{ if(x < 0) //程序出現(xiàn)了問題 //手動(dòng)拋出異常 throw new Exception("程序出現(xiàn)了異常了"); else System.out.println("程序正常"); } }
四始赎、多層異常的處理
demo
/*
多層的異常處理方法調(diào)用
*/
class ExceptionDemo3
{
public static void main(String[] args)
{
//System.out.println("Hello World!");
try{
methodA();
}catch(Exception e){
}
}
public static void methodA()throws Exception{
methodB();
}
public static void methodB()throws Exception{
methodC();
}
public static void methodC()throws Exception{
throw new Exception();
}
}
五、finally代碼塊
- finally可以跟隨try出現(xiàn)仔燕,也可以跟隨try...catch出現(xiàn)
- finally代碼塊中的程序造垛,必須要運(yùn)行
- finally實(shí)際的開發(fā)意義,釋放資源
demo
/*
finally代碼塊
一定要執(zhí)行
*/
class ExceptionDemo4
{
public static void main(String[] args)
{
try{
method(1);
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("這里的程序必須執(zhí)行");
}
}
public static void method(int x)throws Exception{
if(x == 1)
throw new Exception("異常了!!");
else
System.out.println("程序正常了");
}
}
一個(gè)finally的特例:
/*
demo:true or false
*/
class ExceptionDemo5{
public static void main(String[] args){
System.out.println(method());
}
public static boolean method(){
try{
return false;
}catch(Exception e){
}finally{
return true;
}
}
}
//結(jié)果:true
/*
demo2:2 or 10
開發(fā)中晰搀,不要再try catch中寫return
*/
class ExceptionDemo6{
public static void main(String[] args){
System.out.println(method());
}
public static int method(){
int i = 1;
try{
return ++i;
}catch(Exception e){
return 100;
}finally{
i=10;
}
}
}
//結(jié)果:2
六五辽、編譯時(shí)期的異常
調(diào)用一個(gè)方法,這個(gè)方法拋出一個(gè)異常外恕,此時(shí)調(diào)用者必須處理異常杆逗,否則編譯失敗。
Demo
/*
編譯時(shí)期的異常
*/
class ExceptionDemo2{
public static void main(String[] args){
System.out.printf("hello wordl");
method();
}
public static void method() throws Exception{}
}
結(jié)果如下:
ExceptionDemo2.java:10: 錯(cuò)誤: 未報(bào)告的異常錯(cuò)誤Exception; 必須對(duì)其進(jìn)行捕獲或聲明
以便拋出
method();
^
1 個(gè)錯(cuò)誤
改進(jìn)鳞疲,加上try catch對(duì)異常進(jìn)行處理罪郊,錯(cuò)誤提示消失。
/*
編譯時(shí)期的異常
*/
class ExceptionDemo2{
public static void main(String[] args){
System.out.printf("hello wordl");
try{
method();
}catch(Exception e){}
}
public static void method() throws Exception{}
}
七尚洽、運(yùn)行時(shí)期的異常
運(yùn)行時(shí)期的異常一旦發(fā)生了悔橄,后面的所有程序都不會(huì)接著往下執(zhí)行,所以設(shè)計(jì)運(yùn)行時(shí)期的異常的初衷就很明顯了,這個(gè)異常就是讓開發(fā)人員看的癣疟,發(fā)生運(yùn)行異常挣柬,就必須去修改原代碼,而不是去處理異常睛挚。
Demo
/*
運(yùn)行時(shí)期的異常的特點(diǎn)
*/
class ExceptionDemo3{
public static void main(String[] args){
//調(diào)用者不知道方法會(huì)出現(xiàn)異常邪蛔,所以就不用處理
//這種時(shí)候,需要修改代碼扎狱,而不需要處理
method();
}
public static void method(){
//手動(dòng)拋出一個(gè)異常
throw new RuntimeException();
}
}
Demo2
/*
要求:計(jì)算正方形面積侧到,邊長的平方
定義方法:求面積,返回結(jié)果
*/
class ExceptionDemo4{
public static void main(String[] args){
System.out.println(method(-8));
}
public static int method(int num){
if(num <= 0){
//邊長不合法淤击,沒有必要計(jì)算
throw new RuntimeException("<= 0");
}
return num * num;
}
}
常見的運(yùn)行時(shí)期的異常:
異常對(duì)象 | 實(shí)際含義 |
---|---|
IndexOutOfBoundsException | 越界(字符串床牧,和數(shù)組) |
NullPointerException | 空指針 |
ClassCastException | 類型轉(zhuǎn)換異常 |
NoSuchElementException | 沒有元素被取出 |
IllegalArgumentException | 無效參數(shù)異常 |
八、自定義異常
Java中異常體系遭贸,將很多的情況都做了異常封裝,但是實(shí)際的開發(fā)中心软,不可能把所有的異常都描述完畢壕吹,需要自定義的異常,用來描述自己程序中可能發(fā)生的異常删铃。
自定義異常步驟:
- 定義類耳贬,后綴名Exception繼承Exception類,或者繼承RuntimeException
- 異常信息猎唁,自定義的異常類的構(gòu)造方法咒劲,把異常信息使用super傳遞到父類
注意:只有異常類,才具備可拋性 throw new 異常體系的類
通過剛才案例:
- 如果一個(gè)方法中诫隅,拋出多個(gè)異常腐魂,必須要throws聲明多個(gè)異常(運(yùn)行時(shí)起除外)
- 調(diào)用者,使用多個(gè)catch進(jìn)行異常的捕獲
- 多個(gè)catch中逐纬,最大(繼承關(guān)系)的父類蛔屹,寫在最后面,否則編譯失敗
Demo
package exceptions;
/*
* 自定義異常
*/
//負(fù)數(shù)異常
class FuShuException extends Exception{
FuShuException(){}
FuShuException(String info){
super(info);
}
}
//0異常
class ZeroException extends Exception{
ZeroException(){}
ZeroException(String message){
super(message);
}
}
public class ExceptionDemo5 {
public static void main(String[] args) {
try{
getArea(0);
}catch(FuShuException e){ //多異常豁生,就多catch兔毒,范圍越大的往后寫
e.printStackTrace();
}catch(ZeroException e){
e.printStackTrace();
}
}
public static int getArea(int num) throws FuShuException,ZeroException{
if(num < 0){
throw new FuShuException("邊長是負(fù)數(shù)");
}
else if(num == 0){
throw new ZeroException("邊長為0");
}
return (int)Math.pow(num,2);
}
}
九、繼承異常
前提:子類重寫父類的方法
- 父類的方法拋出了異常甸箱,子類重寫后育叁,異常:父類拋異常,子類可拋可不拋芍殖,但是豪嗽,如果子類拋,不能拋出比父類還大的異常
- 父類的方法不拋異常,子類重寫后昵骤,子類不能拋出異常树碱。如果子類重寫的方法中,調(diào)用了一個(gè)拋異常的方法变秦,子類別無選擇成榜,只能
try...catch
處理異常
demo
package exceptions;
/*
* 自定義異常
* 1.父類方法拋異常,子類重寫后可拋可不拋蹦玫,若是拋赎婚,則要小于父類(前提是子類重寫了父類方法)
* 2.父類方法不拋異常,子類也不能拋樱溉,若是子類調(diào)用的方法拋了異常挣输,子類只能try catch
*/
//A是父類異常類
class AException extends Exception{
}
//B繼承A
class BException extends AException{
}
//C和A是兄弟類
class CException extends Exception{
}
class Zi extends Fu{
public void show() throws BException{}
}
class Fu{
public void show() throws AException{}
}
public class ExceptionDemo6 {
public static void main(String[] args) throws AException{
Fu f = new Zi();
f.show();
}
}