異常體系
Error
Java虛擬機(jī)無法解決的嚴(yán)重問題。如:JVM系統(tǒng)內(nèi)部錯(cuò)誤、資源耗盡等嚴(yán)重情況烟勋。比如:StackOverflowError和OOM。一般不編寫針對性的代碼進(jìn)行處理筐付。
public static void main(String[] args) {
// error:
// 棧溢出 java.lang.StackOverflowError
main(args);
// 堆溢出 java.lang.OutOfMemoryError
Integer[] arr = new Integer[1024*1024*1024];
}
Exception
其它因編程錯(cuò)誤或偶然的外在因素導(dǎo)致的一般性問題卵惦,可以使用針對性的代碼進(jìn)行處理。例如:
- 空指針訪問
- 試圖讀取不存在的文件
- 網(wǎng)絡(luò)連接中斷
- 數(shù)組角標(biāo)越界
Exception可分為編譯時(shí)異常與運(yùn)行時(shí)異常
編譯時(shí)異常(受檢異常):
- 是指編譯器要求必須處置的異常瓦戚。即程序在運(yùn)行時(shí)由于外界因素造成的一般性異常沮尿。編譯器要求Java程序必須捕獲或聲明所有編譯時(shí)異常。
- 對于這類異常伤极,如果程序不處理蛹找,可能會帶來意想不到的結(jié)果姨伤。
運(yùn)行時(shí)異常(非受檢異常):
- 是指編譯器不要求強(qiáng)制處置的異常哨坪。一般是指編程時(shí)的邏輯錯(cuò)誤,是程序員應(yīng)該積極避免其出現(xiàn)的異常乍楚。java.lang.RuntimeException類及它的子類都是運(yùn)行時(shí)異常当编。
- 對于這類異常,可以不作處理徒溪,因?yàn)檫@類異常很普遍忿偷,若全處理可能會對程序的可讀性和運(yùn)行效率產(chǎn)生影響。
常見異常
空指針異常 NullPointerException
@Test
public void test1(){
int[] arr = null;
int num = arr[1];
}
數(shù)組/字符串角標(biāo)越界 ArrayIndexOutOfBoundsException / StringIndexOutOfBoundsException
@Test
public void test2(){
String str = "abc";
char c = str.charAt(3);
}
類轉(zhuǎn)換異常 ClassCastException
@Test
public void test3(){
Object obj = new Date();
String str = (String)obj;
}
數(shù)學(xué)運(yùn)算異常 ArithmeticException
@Test
public void test4(){
int i = 10;
int j = 0;
int num = i / j;
}
數(shù)字格式化異常 NumberFormatException
@Test
public void test5(){
String s = "abc";
int num = Integer.parseInt(s);
System.out.println(num);
}
異常處理1:try-catch-finally
java異常處理采用“抓拋模型”:
- 過程一臊泌,拋:程序正常執(zhí)行過程中鲤桥,一旦出現(xiàn)異常,就會在異常代碼處生成一個(gè)對應(yīng)的異常對象并將此對象拋出渠概。一旦拋出對象以后茶凳,其后的代碼不再執(zhí)行
- 過程二,抓:異常處理的方式 try_catch_finally 或 throws
try{
// 可能出現(xiàn)異常的代碼
}catch(異常類型1 變量名1){
// 處理異常的方式1
}catch(異常類型2 變量名2){
// 處理異常的方式2
}
...
finally{
// 一定會執(zhí)行的代碼
}
try_catch:
- 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、常用的異常對象處理的方式:
- sysout String
- getMessage()
- printStackTrace() - 6半开、 在try結(jié)構(gòu)中聲明的變量混滔,出了try結(jié)構(gòu)以后便無法繼續(xù)使用
finally:
- 1、finally是可選的
- 2征冷、finally中聲明的是一定會執(zhí)行的代碼择膝。即使catch中又出現(xiàn)異常,又或者try检激、catch中出現(xiàn)return語句等情況
- 3肴捉、數(shù)據(jù)庫連接、輸入輸出流叔收、網(wǎng)絡(luò)編程中的socket資源等齿穗,jvm是無法自動回收的,需要手動進(jìn)行釋放操作饺律,此操作需要在finally中進(jìn)行
- 4窃页、try_catch_finally可以進(jìn)行嵌套
public void test2(){
FileInputStream fis = null;
try {
File file = new File("hello.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();
}
}
}
體會1:使用try_catch_finally處理編譯時(shí)異常,使得程序在編譯階段不會報(bào)錯(cuò)复濒;但程序在運(yùn)行時(shí)仍然有可能報(bào)錯(cuò)脖卖;相當(dāng)于用try_catch_finally將一個(gè)編譯時(shí)可能出現(xiàn)的異常,延遲到了運(yùn)行時(shí)出現(xiàn)
體會2:由于開發(fā)中運(yùn)行時(shí)異常比較常見巧颈,我們不會編寫針對它的異常處理畦木;對于編譯時(shí)異常,我們才會考慮其異常處理
異常處理2:throws
throws + 異常類型
寫在方法聲明處砸泛,指明當(dāng)方法執(zhí)行時(shí)十籍,可能拋出的異常類型
一旦該方法體執(zhí)行時(shí),出現(xiàn)異常晾嘶,仍會在異常代碼處生成一個(gè)異常類的對象妓雾,此對象滿足throws后面的異常類型時(shí),就會被拋出垒迂。并且后續(xù)的代碼不會被執(zhí)行
總的來說械姻,try_catch_finally會確實(shí)地將異常給處理掉,而throws只是將異常拋給了方法的調(diào)用者,并沒有真正處理異常
public class Throws {
public static void main(String[] args) {
try{
method2();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
public static void method2() throws FileNotFoundException,IOException{
method();
}
public static void method() throws FileNotFoundException,IOException{
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();
}
}
手動拋出異常:throw
Java異常類對象除在程序執(zhí)行過程中出現(xiàn)異常時(shí)由系統(tǒng)自動生成并拋出楷拳,也可根據(jù)需要使用人工創(chuàng)建并拋出
// 手動拋出異常
public class Throw {
public static void main(String[] args) {
try{
Student s = new Student();
s.getID(-1001);
System.out.println(s.toString());
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
class Student{
private int ID;
public void getID(int ID) throws Exception{
if(ID >= 0)
this.ID = ID;
else
// System.out.println("輸入的值非法绣夺!");
// throw new RuntimeException("輸入的值非法!");
throw new Exception("輸入的值非法欢揖!");
}
@Override
public String toString() {
return "Student [ID=" + ID + "]";
}
}
【子類重寫的方法】拋出的異常類型不能大于【父類被重寫的方法】拋出的異常類型
public class OverrideTest {
public static void main(String[] args) {
OverrideTest test = new OverrideTest();
test.display(new SubClass());
}
public void display(SuperClass s){
try {
s.method();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass{
public void method() throws IOException{ };
}
class SubClass extends SuperClass{
public void method() throws FileNotFoundException{ };
}
自定義異常
用戶自定義異常類MyException陶耍,用于描述數(shù)據(jù)取值范圍錯(cuò)誤信息。用戶自己的異常類必須繼承現(xiàn)有的異常類她混。
- 一般地烈钞,用戶自定義異常類都是RuntimeException的子類。
- 自定義異常類通常需要編寫幾個(gè)重載的構(gòu)造器坤按。
- 自定義異常需要提供serialVersionUID
- 自定義的異常通過throw拋出毯欣。
- 自定義異常最重要的是異常類的名字,當(dāng)異常出現(xiàn)時(shí)臭脓,可以根據(jù)名字判斷異常類型酗钞。
public class MyException extends RuntimeException{
static final long serialVersionUID = -317519865L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}