異常的概述和體系
1. 什么是異常?
異常是程序在編譯或者執(zhí)行的過程中可能出現(xiàn)的問題
異常是應(yīng)該盡量提前避免的
異常可能也是無法做到絕對避免的,異衬嫒ぃ可能有太多情況了,開發(fā)中只能提前干預(yù)
異常一旦出現(xiàn)了,程序就會推出JVM虛擬機而終止,開發(fā)中異常是需要提前處理的
研究異常并且避免異常,然后提前處理異常,體系的是程序的健壯性!!!
Java會為常見的代碼異常都設(shè)計一個類來代表
2. 異常的體系
- Java中異常繼承的根類是: Throwable(根類不是異常類)
- Error
- 錯誤的意思,嚴重錯誤Error,無法通過處理的錯誤,一旦出現(xiàn),程序員無能為力,只能重啟系統(tǒng),優(yōu)化項目(比如內(nèi)存奔潰,JVM本身奔潰等,這個程序員無須理會)
- Exception
- 異常類,他是開發(fā)中代碼在編譯或者執(zhí)行過程中可能出現(xiàn)的錯誤,他是需要提前處理的.一邊程序更健壯!
3. Exception異常的分類
- 編譯時異常
- 繼承自Exception的異陈渲瘢或者其子類,編譯階段就會報錯,必須程序員處理,否則代碼編譯就報錯!
- RuntimeException(運行時異常)
- 繼承自RuntimeExce的異橙Υ遥或者其子類,編譯階段是不會出錯的,他是在運行時階段可能出現(xiàn),運行時異郴秸幔可以處理也可以不處理,編譯階段是不會出錯的,但是還是建議處理!
4. 小結(jié)
- 異常類: Exception
- 異常需要處理的,否則異常出現(xiàn)后,程序會死亡
- 異常分為兩類: 編譯時異常,運行時異常
- 編譯時異常編譯階段就直接報錯,程序員必須處理
- 運行時異常編譯階段不報錯,運行階段才報錯!
常見的運行時異常
1. 數(shù)組索引越界異常
? ArrayIndexOutOfBoundsException
int[] arr1 = {10, 20 , 30};
System.out.println(arr1[0]);
System.out.println(arr1[1]);
System.out.println(arr1[2]);
System.out.println(arr1[3]); // 出異常了!
2. 空指針異常
? NullPointerException
// 直接輸出沒有問題.但是調(diào)用空指針的變量的功能就會報錯!String name = null
System.out.println(name); // 空指針直接輸出沒有問題,直接輸出沒有地址的類型:null
System.out.println(name.length());// 出異常了!
3. 類型轉(zhuǎn)換異常
? ClassCaseException
Object obj = "你好";
Integer it = (Integer) obj; //報錯了
4. 迭代器遍歷沒有此元素異常
? NoSuchElementException
List<String> lists = new ArrayList<>();
Collections.addAll(lists,"java1" ,"java2" ,"java2");
Iterator<String> it = lists.iterator();
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next()); // 出異常了!
5. 數(shù)字操作異常
? ArithmeticException
int c = 10 / 0 ; // 出異常了!
System.out.println(c);
?
6. 數(shù)字轉(zhuǎn)換異常
? NumberFormatException
String num = "12dsd";
int n = Integer.valueOf(num); // // 出異常了!
System.out.println(n);
7. 小結(jié)
- 運行時異常都是繼承自RuntimeException,編譯階段不會報錯,運行時才會出現(xiàn)
- 異常一旦出現(xiàn)了,假如沒有處理,程序會立即在出現(xiàn)異常的地方死亡
- 運行時異常一般都是程序員技術(shù)太長(或者思考的不縝密)引起的
編譯時異常認識
- 繼承自Exception的異程视鳎或者其子類,沒有繼承RuntimeException
- 編譯階段就會報錯,必須程序員處理的.否則代碼編譯就報錯!
- 是在編譯階段就直接報錯的,目的是擔心寫代碼的程序員技術(shù)不行,提示你在這里可能很容易出現(xiàn)錯誤,需要注意!
- 運行時異常一般是程序員自己寫代碼引起的
- 編譯時異常是體現(xiàn)程序員這里的代碼要注意,可能出錯,提醒的更強烈!
- 編譯時異常是編譯階段就直接報錯,一定要程序員在編譯階段處理的
異常的產(chǎn)生處理的默認過程
1. 過程解析
- 默認會在出現(xiàn)異常的代碼那里自動的創(chuàng)建一個異常對象: RuntimeException
- 異常會從方法中出現(xiàn)的點這里拋出給調(diào)用者,調(diào)用者最終拋出給JVM虛擬機
- 虛擬機接收的異常對象后,先在控制臺直接輸出異常棧信息數(shù)據(jù)
- 直接干掉當前程序
- 后續(xù)代碼沒有機會執(zhí)行了,因為程序以及死亡
2. 小結(jié)
- 異常默認的處理機制是自動創(chuàng)建異常對象,拋出給調(diào)用者,調(diào)用者拋給虛擬機
- 虛擬機先打印出異常信息,然后直接干掉程序
- 默認的處理機制會引起程序的死亡,不夠健壯,所有程序員要自己提前處理異常
編譯時異常的處理機制
1. 格式
? 拋出
? throws 異常
? 捕獲
? try{}catch(Exception e){}
2. 方式
- 方式一
- 在出現(xiàn)異常的地方,一層一層的拋出給調(diào)用者,調(diào)用者拋出給JVM虛擬機
- 方式二
- 自己捕獲處理
- 優(yōu)點: 及時程序真的出現(xiàn)了異常,自己捕獲處理了,不會引起程序的死亡
- 方式三
- 在出現(xiàn)異常的地方把異常一層異常的拋出給最外層調(diào)用者,最外層調(diào)用者捕獲處理!(規(guī)范做法)
- 小結(jié)
- 最規(guī)范的方式,推薦使用
- 外層可以知道底層執(zhí)行的情況
- 即使出現(xiàn)了錯誤也不會引起程序員的死亡,這是最好的方案
運行時異常的處理機制
- 運行時異常在編譯階段是不會報錯,在運行階段才會出錯
- 運行時異常在編譯階段不處理也不會報錯,但是運行時如果出錯了程序還是會死亡
- 所以運行時異常也要處理
- 運行時異常是自動往外拋出的,不需要我們手工拋出
- 直接在最外層捕獲處理即可,底層會自動拋出
finally關(guān)鍵字
1. 格式
try{
代碼塊
}catch(異常類型 e){
處理
}finally{
代碼塊
}
2. 用途
- finally無論程序正常執(zhí)行還是異常執(zhí)行,都要執(zhí)行一次
- 一般是用來在程序執(zhí)行結(jié)束后,進行資源的回收操作
異常的注意事項
- 運行時異常被拋出可以不處理,可以自動拋出,編譯時異常必須處理,按照規(guī)范都應(yīng)該處理
- 如果父類拋出了多個異常,子類覆蓋父類方法時,只能拋出相同的異常或者是他的子集
- 父類方法沒有拋出異常,子類覆蓋父類該方法時也不可拋出異常.此時子類產(chǎn)出該異常,只能捕獲處理,不能聲明拋出
- 當多異常處理時,捕獲處理,前邊的類不能是后邊類的父類
- try/catch后可以追加finally代碼塊,其中的代碼一定會被執(zhí)行,通常用于資源回收
自定義異常
1. 自定義編譯時異常
- 定義一個異常類繼承Exception
- 重寫構(gòu)造器
- 在出現(xiàn)異常的地方用throw new自定義對象拋出
- 提醒更加強烈,一定需要處理!!
2. 自定義運行時異常
- 定義一個異常類繼承RuntimeException
- 提醒不強烈,編譯階段不報錯!!
- 重寫構(gòu)造器
- 在出現(xiàn)異常的地方用throw new 自定義對象拋出
?
多線程
1. 什么是進程?
- 程序是靜止的,運行中的程序就是進程進程的
- 三個特征
- 動態(tài)性
- 進程是運行中的程序,要冬天的占用內(nèi)存,CPU和網(wǎng)絡(luò)等資源
- 獨立性
- 進程與進程之間的相互獨立的,彼此有自己的獨立內(nèi)存空間
- 并發(fā)性
- 加入CPU是單核,同一個時刻其實內(nèi)存中只有一個進程在被執(zhí)行.
- CPU會分時輪詢切換依次為每個進程服務(wù),因為切換的速度非橙刚快,給我們的感覺這些進程在同時執(zhí)行,這就是并發(fā)性.
- 動態(tài)性
- 并行
- 同一個時刻在同時執(zhí)行
2. 什么是線程?
- 線程是屬于進程的.一個進程可以包含多個線程,這就是多線程
- 線程創(chuàng)建開銷相對于進程來說比較小
- 線程也支持并發(fā)性
3. 線程的作用:
- 可以提高程序的效率,可以有更多機會得到CPU
- 多線程可以解決很多業(yè)務(wù)模型
- 大型高并發(fā)技術(shù)的核心技術(shù),設(shè)計到多線程的開發(fā)可能都比較難理解
4. 小結(jié):
- 進程是運行中的程序.有動態(tài)性,獨立性,并發(fā)性
- 一個進程可以包含多個線程,線程也支持并發(fā)
- 多線程可以提供程序的整體效率,線程也支持并發(fā)
- 多線程可以提高程序的整體效率,可以解決很多業(yè)務(wù)需求
- 因為多個線程是并發(fā)搶占CPU執(zhí)行,所以多線程的執(zhí)行會出現(xiàn)隨機性
創(chuàng)建多線程的方式
1. 方式一
- 步驟
- 定義一個線程類繼承Thread類
- 重新Thread類的run()方法
- 創(chuàng)建一個子線程對象
- 調(diào)用線程對象的start()方法啟動線程(其實最終就是執(zhí)行線程對象的run()方法)
- 線程的注意
- 啟動線程不能直接調(diào)用run()方法,否則就是普通對象的普通方法調(diào)用,失去線程特征
- 線程的啟動必須調(diào)用start()
- 一般是先創(chuàng)建子線程,再申明主線程的任務(wù),否則主線程任務(wù)總是先執(zhí)行完
- 優(yōu)缺點
- 優(yōu)點: 代碼簡單
- 缺點
- 已經(jīng)繼承了Thread類,不能再繼承其他類,功能被削弱
- 不能做線程池
- 無法直接返回線程執(zhí)行的結(jié)果
- 方式二
- 步驟
- 定義一個線程任務(wù)類實現(xiàn)Runnable接口.重新run()方法
- 創(chuàng)建一個線程任務(wù)對象
- 把線程任務(wù)對象包裝成一個線程對象
public Thread(Runnable target)
- 調(diào)用線程對象的start()方法啟動線程
- 優(yōu)缺點
- 缺點: 編程相對復(fù)雜,不能直接返回線程對象
- 優(yōu)點
- 一個任務(wù)對象可以被反復(fù)包裝成多個線程對象
- 可以避免java中的單繼承的局限性.因為線程任務(wù)對象只是實現(xiàn)了接口,還可以繼續(xù)繼承其他類和實現(xiàn)其他接口
- 實現(xiàn)解耦操作,線程任務(wù)對象代碼可以被多個線程共享,代碼和線程獨立
- 線程池只能放入實現(xiàn)Runable或Callable類線程,不能直接放入繼承Thread的類
- 適合做線程池
3. 方式三
- 步驟
- 定義一個線程任務(wù)類實現(xiàn)Callable接口
- 重新Call()方法
- 把線程對象任務(wù)包裝成一個未來任務(wù)對象
- 把未來任務(wù)對象包裝成一個線程對象
- 調(diào)用線程對象的start()方法啟動線程
- 優(yōu)缺點
- 缺點: 編碼復(fù)雜
- 優(yōu)點
- 可以繼續(xù)繼承其他類
- 可以做線程池
- 可以得到線程返回結(jié)果
- 可以做資源共享操作
線程的常用API
線程是有默認名字的: 子線程的名稱規(guī)則Thread_索引,main線程的默認名稱就是main
-
API
1. public void setName(String name) // 給線程對象取名字 2. public String getName() // 返回線程對象的名字 3. public static Thread currentThread() // 獲取當前線程對象,這個代碼是哪個線程在執(zhí)行就返回哪個線程對象