day05_面向對象(異常、線程)
一.異常
1.什麼是異常
代碼執行過程中的出現的問題
ArrayIndexOutOfBoundsException
NullPointerExceptioin
2.異常的繼承體系*************
Throwable 異常的根類
- Error 錯誤類
- Exception 異常類
-編譯時異常 Exception類以及其子類(RuntimeException除外)
-運行時異常 RuntimeException以及其子類
3.異常類中常用的三個方法
public void printStackTrace():打印異常的詳細信息(包括異常信息、異常原因以及異常位置)*****************
public String getMessage():獲取異常的原因
public String toString():返回異常的類型和異常的信息
4.異常的分類
i.編譯時異常
Exception類以及其子類(RuntimeException除外)
編譯時異常,會在編譯時報錯!!!
ii.運行時異常
RuntimeException以及其子類
運行時異常,編譯器不報錯,直到運行時才報錯!!!
5.JVM異常產生過程(畫圖演示)
二.異常的處理
1.模擬JVM拋出異常(關鍵字throw)
throw:表示拋出一個異常對象會中斷處理(結束程序運行)
格式:
throw 異常對象;
public class ExceptionDemo02 {
public static void main(String[] args) {
//調用方法
int[] arr = null;
method(arr);
}
//模擬JVM拋出異常
public static void method(int[] arr) {
//判斷 arr 是不是 null
if (arr == null) {
throw new NullPointerException("哥們您的數組是null啊~~~~");
}
//判斷 arr 有沒有第二個元素
if (arr.length <= 1) {
throw new ArrayIndexOutOfBoundsException("哥們您的數組要越界了~~~~");
}
//取出第二個元素
int num = arr[1];
System.out.println(num);
}
}
2.Objects類中提供的非空判斷方法
Objects類是一個工具類,所有的方法都是靜態的
public static<T> T requireNonNull(T obj){
if (obj == null){
throw new NullPointerException();
}
return obj;
}
3.遇到異常的的兩種處理方式******************
①throws聲明拋出異常
throws這個關鍵字使用修飾修飾方法的,聲明該方法的調用者必須處理異常
格式:
public static void 方法名(參數列表)throws 異常類名1,異常類名2,...{
}
第一種處理方式:不處理,再次聲明拋出
②try...catch捕獲異常 (允許程序局部異常,代碼正常運行)
第二種處理方式:捕獲處理,把異常對象抓住
格式:
try{
可能出現異常的代碼
}catch (XxxException e){
自己處理異常對象e
}
之後能正常運行代碼
4.[擴展1]catch代碼塊中三種常見的處理方法
a.在開發階段:直接打印到控制檯
b.在測試階段:寫到日誌文件中或數據庫中
c.在上線階段:先把錯誤日誌保存到本地,在適當的時機上傳到服務器(連接wifi的時候)
5.[擴展2]多個異常如何獲取處理
method01():可能拋出OneException
method02():可能拋出TwoException
method03():可能拋出ThreeException
a.第一種方式:每個異常單獨處理
try{
method01(); // 可能拋出OneException
}catch(OneException e){
e.printStackTrace();
}
try{
method02(); // 可能拋出TwoException
}catch(TwoException e){
e.printStackTrace();
}
try{
method03(); // 可能拋出ThreeException
}catch(ThreeException e){
e.printStackTrace();
}
b.第二種方式:多個異常統一處理*******(用的最多)
try{
method01(); //可能拋出OneException
method02(); //可能拋出TwoException
method03(); //可能拋出ThreeException
}catch(Exception e){ //異常類型應該是以上可能異常的父類
e.printStackTrace();
}
c.第三種方式:多個異常分別處理
try{
method01(); //可能拋出OneException
method02(); //可能拋出TwoException
method03(); //可能拋出ThreeException
}catch(OneException e1){
直接打印
}catch(TwoException e2){
寫到異常日誌
}catch(ThreeException e3){
不管他
}
注意:
假設OneException是TwoException的子類,那麼在catch必須先catch子類異常對象,再catch父類異 常對象,因爲多態,如果TwoException放在OneException前面,OneException和TwoException均會被TwoException處理方法catch,OneException的處理方法catch不到異常
6.finally代碼塊
finally被稱爲必須要執行的代碼塊
格式:
try{
可能出現異常的代碼
}catch(XxxException e){
處理異常
}finally{
必須要執行的代碼
}
必須要執行的代碼是指釋放資源的代碼
比如:關閉文件的IO流(不關閉下次文件無法打開),關閉數據庫連接,關閉網絡連接(網絡服務器的連接個數有限)。
流氓軟件原理:後臺總會開啓一個程序或線程,所以你無法卸載。
三線程守護:有三個線程同時在後臺運行,一旦一個線程被關閉,其他兩個線程又會把他打開。
文件粉碎:不管程序有沒有運行,強制在操作系統的層面上進行文件刪除操作。
7.異常的注意事項
a.運行時異常,在編譯階段不需要聲明也不需要捕獲
b.父類的方法拋出多個異常,子類在重寫該方法只能拋出這些異常的子集
c.如果父類的方法沒有拋出異常,子類重寫該方法時必須也不能拋出異常
d.如果有多個catch,那麼必須先catch子類異常,再catch父類異常
e.trycatch後面可以finally,一般用於資源回收
f.多個異常如何捕獲處理
i.每個異常單獨catch
ii.多個異常一個try一個catch
iii.多個異常一個try多個catch
總結:
a.如果寫代碼過程中,沒有異常,就當作沒學一樣
b.如果遇到編譯時異常,要麼throw要麼try
c.如果遇到運行時異常,運行時程序程序崩潰了根據異常信息修改代碼
三.自定義異常
1.爲什麼要定義異常
因爲JDK所定義的異常類不可能描述所有問題,所以需要自定義異常
2.自定義異常的步驟
a.創建一個異常類,該類必須叫做XxxException
b.該類必須繼承Exception或者RuntimeException
c.自定義異常類至少提供兩個構造
i.空參構造
ii.帶有異常信息的String參數構造
//1.異常類以Exception結尾
public class MyException extends /*Exception*/ RuntimeException { //2.繼承Exceptoin 或者 RuntimeException
//2.提供兩個構造
public MyException(){}
public MyException(String message){
super(message);
}
}
3.自定義異常的練習(代碼演示)
/**
* 用戶名已經存在異常:
* 描述註冊時用戶名存在這種情況
*/
public class UserNameExistsException extends Exception{
public UserNameExistsException() {
}
public UserNameExistsException(String message) {
super(message);
}
}
public class TestDemo {
public static void main(String[] args) {
//模擬註冊
System.out.println("請輸入一個用戶名:");
String username = new Scanner(System.in).nextLine();
// 調用方法
try {
register(username);
} catch (UserNameExistsException e) {
e.printStackTrace();
}
}
//定義方法:註冊用戶
public static void register(String username) throws UserNameExistsException {
//查詢數據庫,該用戶名是否被註冊過
//假設 jack 這個用戶已經被註冊了
if (username.equals("jack")) {
//不能註冊
throw new UserNameExistsException("親,該用戶名已經被註冊~~~");
} else{
System.out.println("恭喜您"+username+"註冊成功~~~");
}
}
}
四.多線程************************
1.並行和併發
並行:兩個事件同一時刻都在進行
併發:兩個事件同一時間段內存都在進行,精確到時刻是交替運行
2.進程和線程:
進程:在內存中正在運行的程序
線程:進程中完成特定功能的執行單元
進程和線程的一些區別(瞭解)
a.一個進程中可能包含多個線程,這種有多個線程的進程,我們稱爲多線程進程,對應的有單線程進程
b.進程用戶獨立的堆和獨立的棧(進程間可以通過操作系統進行通信,JDNI)
c.線程也擁有獨立的棧,但是線程共享進程的堆(線程之間可以互相通信)
線程調度
常識:一個單核的CPU,在同一時刻只能執行一條線程
線程調度:CPU在多個線程之間進行快速切換(併發的由來)
線程調度分類:
分時調度:每個線程拼接分配CPU的時間
搶佔式調度:每個線程隨機分配CPU的時間
Java進程中多個線程採取搶佔式調度
3.創建新的線程方式一
當我們運行一個Java程序時,就是一個Java進程
這個進程中默認有至少兩個線程:
第一個:main方法所在的線程,稱爲主線程
第二個:gc線程(垃圾回收線程)
如何創建一個新的線程呢???
Java中提供了一個代表線程的類,稱爲Thread類
API的描述:
一種方法是將類聲明爲Thread子類
該子類應重寫Thread類的run方法
接下來可以分配並啓動該子類的實例
a.定義一個類繼承Thread類
b.重寫run方法(就是寫線程任務代碼的地方)
c.創建子類對象(就是一個線程對象)
d.啓動線程(調用start方法即可)
//1.繼承
public class MyThread extends Thread {
//2.重寫run
@Override
public void run() {
//1.喫飯
for (int i = 0; i < 20; i++) {
System.out.println("喫飯"+i);
}
}
}
public class TestDemo {
public static void main(String[] args) {
//3.創建線程對象
MyThread mt = new MyThread();
//4.啓動線程
mt.start();
//2.聽歌
for (int i = 0; i < 20; i++) {
System.out.println("聽歌"+i);
}
}
}
總結:
-[] 能夠辨別程序中異常和錯誤的區別
-[] 說出異常的分類
Throwable
Error
Exception
編譯時異常
運行時異常
-[] 說出虛擬機處理異常的方式
中斷處理
a.停止運行
b.直接打印
-[] 列舉出常見的三個運行期異常
ArrayIndexOutOfBoundsException
NullPoiinterException
ClassCastException
-[] 能夠使用try...catch關鍵字處理異常********
-[] 能夠使用throws關鍵字處理異常*********
-[] 能夠自定義異常類
-[] 能夠處理自定義異常類
-[] 說出進程的概念********
-[] 說出線程的概念********
-[] 能夠理解併發與並行的區別*********
-[] 能夠開啓新線程***************************