JAVA入門筆記~基礎(chǔ)知識day12

異常的概述和體系

1. 什么是異常?

  1. 異常是程序在編譯或者執(zhí)行的過程中可能出現(xiàn)的問題

  2. 異常是應(yīng)該盡量提前避免的

  3. 異??赡芤彩菬o法做到絕對避免的,異??赡苡刑嗲闆r了,開發(fā)中只能提前干預(yù)

  4. 異常一旦出現(xiàn)了,程序就會推出JVM虛擬機而終止,開發(fā)中異常是需要提前處理的

  5. 研究異常并且避免異常,然后提前處理異常,體系的是程序的健壯性!!!

  6. Java會為常見的代碼異常都設(shè)計一個類來代表

2. 異常的體系

  1. Java中異常繼承的根類是: Throwable(根類不是異常類)
  2. Error
    1. 錯誤的意思,嚴(yán)重錯誤Error,無法通過處理的錯誤,一旦出現(xiàn),程序員無能為力,只能重啟系統(tǒng),優(yōu)化項目(比如內(nèi)存奔潰,JVM本身奔潰等,這個程序員無須理會)
  3. Exception
    1. 異常類,他是開發(fā)中代碼在編譯或者執(zhí)行過程中可能出現(xiàn)的錯誤,他是需要提前處理的.一邊程序更健壯!

3. Exception異常的分類

  1. 編譯時異常
    1. 繼承自Exception的異?;蛘咂渥宇?編譯階段就會報錯,必須程序員處理,否則代碼編譯就報錯!
  2. RuntimeException(運行時異常)
    1. 繼承自RuntimeExce的異?;蛘咂渥宇?編譯階段是不會出錯的,他是在運行時階段可能出現(xiàn),運行時異??梢蕴幚硪部梢圆惶幚?編譯階段是不會出錯的,但是還是建議處理!

4. 小結(jié)

  1. 異常類: Exception
  2. 異常需要處理的,否則異常出現(xiàn)后,程序會死亡
  3. 異常分為兩類: 編譯時異常,運行時異常
  4. 編譯時異常編譯階段就直接報錯,程序員必須處理
  5. 運行時異常編譯階段不報錯,運行階段才報錯!

常見的運行時異常

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é)

  1. 運行時異常都是繼承自RuntimeException,編譯階段不會報錯,運行時才會出現(xiàn)
  2. 異常一旦出現(xiàn)了,假如沒有處理,程序會立即在出現(xiàn)異常的地方死亡
  3. 運行時異常一般都是程序員技術(shù)太長(或者思考的不縝密)引起的

編譯時異常認(rèn)識

  1. 繼承自Exception的異?;蛘咂渥宇?沒有繼承RuntimeException
  2. 編譯階段就會報錯,必須程序員處理的.否則代碼編譯就報錯!
  3. 是在編譯階段就直接報錯的,目的是擔(dān)心寫代碼的程序員技術(shù)不行,提示你在這里可能很容易出現(xiàn)錯誤,需要注意!
  4. 運行時異常一般是程序員自己寫代碼引起的
  5. 編譯時異常是體現(xiàn)程序員這里的代碼要注意,可能出錯,提醒的更強烈!
  6. 編譯時異常是編譯階段就直接報錯,一定要程序員在編譯階段處理的

異常的產(chǎn)生處理的默認(rèn)過程

1. 過程解析

  1. 默認(rèn)會在出現(xiàn)異常的代碼那里自動的創(chuàng)建一個異常對象: RuntimeException
  2. 異常會從方法中出現(xiàn)的點這里拋出給調(diào)用者,調(diào)用者最終拋出給JVM虛擬機
  3. 虛擬機接收的異常對象后,先在控制臺直接輸出異常棧信息數(shù)據(jù)
  4. 直接干掉當(dāng)前程序
  5. 后續(xù)代碼沒有機會執(zhí)行了,因為程序以及死亡

2. 小結(jié)

  1. 異常默認(rèn)的處理機制是自動創(chuàng)建異常對象,拋出給調(diào)用者,調(diào)用者拋給虛擬機
  2. 虛擬機先打印出異常信息,然后直接干掉程序
  3. 默認(rèn)的處理機制會引起程序的死亡,不夠健壯,所有程序員要自己提前處理異常

編譯時異常的處理機制

1. 格式

? 拋出
? throws 異常
? 捕獲
? try{}catch(Exception e){}

2. 方式

  1. 方式一
    • 在出現(xiàn)異常的地方,一層一層的拋出給調(diào)用者,調(diào)用者拋出給JVM虛擬機
  2. 方式二
    • 自己捕獲處理
    • 優(yōu)點: 及時程序真的出現(xiàn)了異常,自己捕獲處理了,不會引起程序的死亡
  3. 方式三
    • 在出現(xiàn)異常的地方把異常一層異常的拋出給最外層調(diào)用者,最外層調(diào)用者捕獲處理!(規(guī)范做法)
  4. 小結(jié)
    • 最規(guī)范的方式,推薦使用
    • 外層可以知道底層執(zhí)行的情況
    • 即使出現(xiàn)了錯誤也不會引起程序員的死亡,這是最好的方案

運行時異常的處理機制

  1. 運行時異常在編譯階段是不會報錯,在運行階段才會出錯
  2. 運行時異常在編譯階段不處理也不會報錯,但是運行時如果出錯了程序還是會死亡
  3. 所以運行時異常也要處理
  4. 運行時異常是自動往外拋出的,不需要我們手工拋出
  5. 直接在最外層捕獲處理即可,底層會自動拋出

finally關(guān)鍵字

1. 格式

try{
    代碼塊
}catch(異常類型 e){
    處理
}finally{
    代碼塊
}

2. 用途

  1. finally無論程序正常執(zhí)行還是異常執(zhí)行,都要執(zhí)行一次
  2. 一般是用來在程序執(zhí)行結(jié)束后,進行資源的回收操作

異常的注意事項

  1. 運行時異常被拋出可以不處理,可以自動拋出,編譯時異常必須處理,按照規(guī)范都應(yīng)該處理
  2. 如果父類拋出了多個異常,子類覆蓋父類方法時,只能拋出相同的異?;蛘呤撬淖蛹?/li>
  3. 父類方法沒有拋出異常,子類覆蓋父類該方法時也不可拋出異常.此時子類產(chǎn)出該異常,只能捕獲處理,不能聲明拋出
  4. 當(dāng)多異常處理時,捕獲處理,前邊的類不能是后邊類的父類
  5. try/catch后可以追加finally代碼塊,其中的代碼一定會被執(zhí)行,通常用于資源回收

自定義異常

1. 自定義編譯時異常

  1. 定義一個異常類繼承Exception
  2. 重寫構(gòu)造器
  3. 在出現(xiàn)異常的地方用throw new自定義對象拋出
  4. 提醒更加強烈,一定需要處理!!

2. 自定義運行時異常

  1. 定義一個異常類繼承RuntimeException
  2. 提醒不強烈,編譯階段不報錯!!
  3. 重寫構(gòu)造器
  4. 在出現(xiàn)異常的地方用throw new 自定義對象拋出

?

多線程

1. 什么是進程?

  1. 程序是靜止的,運行中的程序就是進程進程的
  2. 三個特征
    1. 動態(tài)性
      1. 進程是運行中的程序,要冬天的占用內(nèi)存,CPU和網(wǎng)絡(luò)等資源
    2. 獨立性
      1. 進程與進程之間的相互獨立的,彼此有自己的獨立內(nèi)存空間
    3. 并發(fā)性
      1. 加入CPU是單核,同一個時刻其實內(nèi)存中只有一個進程在被執(zhí)行.
      2. CPU會分時輪詢切換依次為每個進程服務(wù),因為切換的速度非???給我們的感覺這些進程在同時執(zhí)行,這就是并發(fā)性.
  3. 并行
    1. 同一個時刻在同時執(zhí)行

2. 什么是線程?

  1. 線程是屬于進程的.一個進程可以包含多個線程,這就是多線程
  2. 線程創(chuàng)建開銷相對于進程來說比較小
  3. 線程也支持并發(fā)性

3. 線程的作用:

  1. 可以提高程序的效率,可以有更多機會得到CPU
  2. 多線程可以解決很多業(yè)務(wù)模型
  3. 大型高并發(fā)技術(shù)的核心技術(shù),設(shè)計到多線程的開發(fā)可能都比較難理解

4. 小結(jié):

  1. 進程是運行中的程序.有動態(tài)性,獨立性,并發(fā)性
  2. 一個進程可以包含多個線程,線程也支持并發(fā)
  3. 多線程可以提供程序的整體效率,線程也支持并發(fā)
  4. 多線程可以提高程序的整體效率,可以解決很多業(yè)務(wù)需求
  5. 因為多個線程是并發(fā)搶占CPU執(zhí)行,所以多線程的執(zhí)行會出現(xiàn)隨機性

創(chuàng)建多線程的方式

1. 方式一

  1. 步驟
    1. 定義一個線程類繼承Thread類
    2. 重新Thread類的run()方法
    3. 創(chuàng)建一個子線程對象
    4. 調(diào)用線程對象的start()方法啟動線程(其實最終就是執(zhí)行線程對象的run()方法)
  2. 線程的注意
  3. 啟動線程不能直接調(diào)用run()方法,否則就是普通對象的普通方法調(diào)用,失去線程特征
  4. 線程的啟動必須調(diào)用start()
  5. 一般是先創(chuàng)建子線程,再申明主線程的任務(wù),否則主線程任務(wù)總是先執(zhí)行完
  6. 優(yōu)缺點
  7. 優(yōu)點: 代碼簡單
  8. 缺點
    1. 已經(jīng)繼承了Thread類,不能再繼承其他類,功能被削弱
    2. 不能做線程池
    3. 無法直接返回線程執(zhí)行的結(jié)果
  1. 方式二
  2. 步驟
    1. 定義一個線程任務(wù)類實現(xiàn)Runnable接口.重新run()方法
    2. 創(chuàng)建一個線程任務(wù)對象
    3. 把線程任務(wù)對象包裝成一個線程對象
      public Thread(Runnable target)
    4. 調(diào)用線程對象的start()方法啟動線程
  3. 優(yōu)缺點
    1. 缺點: 編程相對復(fù)雜,不能直接返回線程對象
    2. 優(yōu)點
      1. 一個任務(wù)對象可以被反復(fù)包裝成多個線程對象
      2. 可以避免java中的單繼承的局限性.因為線程任務(wù)對象只是實現(xiàn)了接口,還可以繼續(xù)繼承其他類和實現(xiàn)其他接口
      3. 實現(xiàn)解耦操作,線程任務(wù)對象代碼可以被多個線程共享,代碼和線程獨立
      4. 線程池只能放入實現(xiàn)Runable或Callable類線程,不能直接放入繼承Thread的類
      5. 適合做線程池

3. 方式三

  1. 步驟
    1. 定義一個線程任務(wù)類實現(xiàn)Callable接口
    2. 重新Call()方法
    3. 把線程對象任務(wù)包裝成一個未來任務(wù)對象
    4. 把未來任務(wù)對象包裝成一個線程對象
    5. 調(diào)用線程對象的start()方法啟動線程
  2. 優(yōu)缺點
    1. 缺點: 編碼復(fù)雜
    2. 優(yōu)點
      1. 可以繼續(xù)繼承其他類
      2. 可以做線程池
      3. 可以得到線程返回結(jié)果
      4. 可以做資源共享操作

線程的常用API

  • 線程是有默認(rèn)名字的: 子線程的名稱規(guī)則Thread_索引,main線程的默認(rèn)名稱就是main

  • API

    1. public void setName(String name)   // 給線程對象取名字
    2. public String getName()    // 返回線程對象的名字
    3. public static Thread currentThread()   // 獲取當(dāng)前線程對象,這個代碼是哪個線程在執(zhí)行就返回哪個線程對象
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容