摘要:表示異常,異常產(chǎn)生后程序員可以通過代碼的方式糾正,使程序繼續(xù)運行,是必須要處理的。獲取發(fā)生異常的原因。需要將這個異常對象告知給調用者。另外,因為異常會引發(fā)程序跳轉,導致有些語句執(zhí)行不到。多個異常一次捕獲,多次處理。
day05 【異常、線程】 主要內容
異常、線程
教學目標[ ] 能夠辨別程序中異常和錯誤的區(qū)別
[ ] 說出異常的分類
[ ] 說出虛擬機處理異常的方式
[ ] 列舉出常見的三個運行期異常
[ ] 能夠使用try...catch關鍵字處理異常
[ ] 能夠使用throws關鍵字處理異常
[ ] 能夠自定義異常類
[ ] 能夠處理自定義異常類
[ ] 說出進程的概念
[ ] 說出線程的概念
[ ] 能夠理解并發(fā)與并行的區(qū)別
[ ] 能夠開啟新線程
第一章 異常 1.1 異常概念異常,就是不正常的意思。在生活中:醫(yī)生說,你的身體某個部位有異常,該部位和正常相比有點不同,該部位的功能將受影響.在程序中的意思就是:
異常 :指的是程序在執(zhí)行過程中,出現(xiàn)的非正常的情況,最終會導致JVM的非正常停止。
在Java等面向對象的編程語言中,異常本身是一個類,產(chǎn)生異常就是創(chuàng)建異常對象并拋出了一個異常對象。Java處理異常的方式是中斷處理。
異常指的并不是語法錯誤,語法錯了,編譯不通過,不會產(chǎn)生字節(jié)碼文件,根本不能運行.1.2 異常體系
異常機制其實是幫助我們找到程序中的問題,異常的根類是java.lang.Throwable,其下有兩個子類:java.lang.Error與java.lang.Exception,平常所說的異常指java.lang.Exception。
Throwable體系:
Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免,好比絕癥。
Exception:表示異常,異常產(chǎn)生后程序員可以通過代碼的方式糾正,使程序繼續(xù)運行,是必須要處理的。好比感冒、闌尾炎。
Throwable中的常用方法:
public void printStackTrace():打印異常的詳細信息。
包含了異常的類型,異常的原因,還包括異常出現(xiàn)的位置,在開發(fā)和調試階段,都得使用printStackTrace。
public String getMessage():獲取發(fā)生異常的原因。
提示給用戶的時候,就提示錯誤原因。
public String toString():獲取異常的類型和異常描述信息(不用)。
出現(xiàn)異常,不要緊張,把異常的簡單類名,拷貝到API中去查。
1.3 異常分類我們平常說的異常就是指Exception,因為這類異常一旦出現(xiàn),我們就要對代碼進行更正,修復程序。
異常(Exception)的分類:根據(jù)在編譯時期還是運行時期去檢查異常?
編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)
運行時期異常:runtime異常。在運行時期,檢查異常.在編譯時期,運行異常不會編譯器檢測(不報錯)。(如數(shù)學異常)
?
1.4 異常的產(chǎn)生過程解析先運行下面的程序,程序會產(chǎn)生一個數(shù)組索引越界異常ArrayIndexOfBoundsException。我們通過圖解來解析下異常產(chǎn)生的過程。
工具類
public class ArrayTools { // 對給定的數(shù)組通過給定的角標獲取元素。 public static int getElement(int[] arr, int index) { int element = arr[index]; return element; } }
測試類
public class ExceptionDemo { public static void main(String[] args) { int[] arr = { 34, 12, 67 }; intnum = ArrayTools.getElement(arr, 4) System.out.println("num=" + num); System.out.println("over"); } }
上述程序執(zhí)行過程圖解:
第二章 異常的處理Java異常處理的五個關鍵字:try、catch、finally、throw、throws
2.1 拋出異常throw在編寫程序時,我們必須要考慮程序出現(xiàn)問題的情況。比如,在定義方法時,方法需要接受參數(shù)。那么,當調用方法使用接受到的參數(shù)時,首先需要先對參數(shù)數(shù)據(jù)進行合法的判斷,數(shù)據(jù)若不合法,就應該告訴調用者,傳遞合法的數(shù)據(jù)進來。這時需要使用拋出異常的方式來告訴調用者。
在java中,提供了一個throw關鍵字,它用來拋出一個指定的異常對象。那么,拋出一個異常具體如何操作呢?
創(chuàng)建一個異常對象。封裝一些提示信息(信息可以自己編寫)。
需要將這個異常對象告知給調用者。怎么告知呢?怎么將這個異常對象傳遞到調用者處呢?通過關鍵字throw就可以完成。throw 異常對象。
throw用在方法內,用來拋出一個異常對象,將這個異常對象傳遞到調用者處,并結束當前方法的執(zhí)行。
使用格式:
throw new 異常類名(參數(shù));
例如:
throw new NullPointerException("要訪問的arr數(shù)組不存在"); throw new ArrayIndexOutOfBoundsException("該索引在數(shù)組中不存在,已超出范圍");
學習完拋出異常的格式后,我們通過下面程序演示下throw的使用。
public class ThrowDemo { public static void main(String[] args) { //創(chuàng)建一個數(shù)組 int[] arr = {2,4,52,2}; //根據(jù)索引找對應的元素 int index = 4; int element = getElement(arr, index); System.out.println(element); System.out.println("over"); } /* * 根據(jù) 索引找到數(shù)組中對應的元素 */ public static int getElement(int[] arr,int index){ //判斷 索引是否越界 if(index<0 || index>arr.length-1){ /* 判斷條件如果滿足,當執(zhí)行完throw拋出異常對象后,方法已經(jīng)無法繼續(xù)運算。 這時就會結束當前方法的執(zhí)行,并將異常告知給調用者。這時就需要通過異常來解決。 */ throw new ArrayIndexOutOfBoundsException("哥們,角標越界了~~~"); } int element = arr[index]; return element; } }
注意:如果產(chǎn)生了問題,我們就會throw將問題描述類即異常進行拋出,也就是將問題返回給該方法的調用者。2.2 Objects非空判斷那么對于調用者來說,該怎么處理呢?一種是進行捕獲處理,另一種就是繼續(xù)講問題聲明出去,使用throws聲明處理。
還記得我們學習過一個類Objects嗎,曾經(jīng)提到過它由一些靜態(tài)的實用方法組成,這些方法是null-save(空指針安全的)或null-tolerant(容忍空指針的),那么在它的源碼中,對對象為null的值進行了拋出異常操作。
public static
查看源碼發(fā)現(xiàn)這里對為null的進行了拋出異常操作:
public static2.3 聲明異常throwsT requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
聲明異常:將問題標識出來,報告給調用者。如果方法內通過throw拋出了編譯時異常,而沒有捕獲處理(稍后講解該方式),那么必須通過throws進行聲明,讓調用者去處理。
關鍵字throws運用于方法聲明之上,用于表示當前方法不處理異常,而是提醒該方法的調用者來處理異常(拋出異常).
聲明異常格式:
修飾符 返回值類型 方法名(參數(shù)) throws 異常類名1,異常類名2…{ }
聲明異常的代碼演示:
public class ThrowsDemo { public static void main(String[] args) throws FileNotFoundException { read("a.txt"); } // 如果定義功能時有問題發(fā)生需要報告給調用者。可以通過在方法上使用throws關鍵字進行聲明 public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//如果不是 a.txt這個文件 // 我假設 如果不是 a.txt 認為 該文件不存在 是一個錯誤 也就是異常 throw throw new FileNotFoundException("文件不存在"); } } }
throws用于進行異常類的聲明,若該方法可能有多種異常情況產(chǎn)生,那么在throws后面可以寫多個異常類,用逗號隔開。
public class ThrowsDemo2 { public static void main(String[] args) throws IOException { read("a.txt"); } public static void read(String path)throws FileNotFoundException, IOException { if (!path.equals("a.txt")) {//如果不是 a.txt這個文件 // 我假設 如果不是 a.txt 認為 該文件不存在 是一個錯誤 也就是異常 throw throw new FileNotFoundException("文件不存在"); } if (!path.equals("b.txt")) { throw new IOException(); } } }2.4 捕獲異常try…catch
如果異常出現(xiàn)的話,會立刻終止程序,所以我們得處理異常:
該方法不處理,而是聲明拋出,由該方法的調用者來處理(throws)。
在方法中使用try-catch的語句塊來處理異常。
try-catch的方式就是捕獲異常。
捕獲異常:Java中對異常有針對性的語句進行捕獲,可以對出現(xiàn)的異常進行指定方式的處理。
捕獲異常語法如下:
try{ 編寫可能會出現(xiàn)異常的代碼 }catch(異常類型 e){ 處理異常的代碼 //記錄日志/打印異常信息/繼續(xù)拋出異常 }
try:該代碼塊中編寫可能產(chǎn)生異常的代碼。
catch:用來進行某種異常的捕獲,實現(xiàn)對捕獲到的異常進行處理。
注意:try和catch都不能多帶帶使用,必須連用。
演示如下:
public class TryCatchDemo { public static void main(String[] args) { try {// 當產(chǎn)生異常時,必須有處理方式。要么捕獲,要么聲明。 read("b.txt"); } catch (FileNotFoundException e) {// 括號中需要定義什么呢? //try中拋出的是什么異常,在括號中就定義什么異常類型 System.out.println(e); } System.out.println("over"); } /* * * 我們 當前的這個方法中 有異常 有編譯期異常 */ public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//如果不是 a.txt這個文件 // 我假設 如果不是 a.txt 認為 該文件不存在 是一個錯誤 也就是異常 throw throw new FileNotFoundException("文件不存在"); } } }
如何獲取異常信息:
Throwable類中定義了一些查看方法:
public String getMessage():獲取異常的描述信息,原因(提示給用戶的時候,就提示錯誤原因。
public String toString():獲取異常的類型和異常描述信息(不用)。
public void printStackTrace():打印異常的跟蹤棧信息并輸出到控制臺。
? 包含了異常的類型,異常的原因,還包括異常出現(xiàn)的位置,在開發(fā)和調試階段,都得使用printStackTrace。
2.4 finally 代碼塊finally:有一些特定的代碼無論異常是否發(fā)生,都需要執(zhí)行。另外,因為異常會引發(fā)程序跳轉,導致有些語句執(zhí)行不到。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執(zhí)行的。
什么時候的代碼必須最終執(zhí)行?
當我們在try語句塊中打開了一些物理資源(磁盤文件/網(wǎng)絡連接/數(shù)據(jù)庫連接等),我們都得在使用完之后,最終關閉打開的資源。
finally的語法:
try...catch....finally:自身需要處理異常,最終還得關閉資源。
注意:finally不能多帶帶使用。
比如在我們之后學習的IO流中,當打開了一個關聯(lián)文件的資源,最后程序不管結果如何,都需要把這個資源關閉掉。
finally代碼參考如下:
public class TryCatchDemo4 { public static void main(String[] args) { try { read("a.txt"); } catch (FileNotFoundException e) { //抓取到的是編譯期異常 拋出去的是運行期 throw new RuntimeException(e); } finally { System.out.println("不管程序怎樣,這里都將會被執(zhí)行。"); } System.out.println("over"); } /* * * 我們 當前的這個方法中 有異常 有編譯期異常 */ public static void read(String path) throws FileNotFoundException { if (!path.equals("a.txt")) {//如果不是 a.txt這個文件 // 我假設 如果不是 a.txt 認為 該文件不存在 是一個錯誤 也就是異常 throw throw new FileNotFoundException("文件不存在"); } } }
當只有在try或者catch中調用退出JVM的相關方法,此時finally才不會執(zhí)行,否則finally永遠會執(zhí)行。2.5 異常注意事項
多個異常使用捕獲又該如何處理呢?
多個異常分別處理。
多個異常一次捕獲,多次處理。
多個異常一次捕獲一次處理。
一般我們是使用一次捕獲多次處理方式,格式如下:
try{ 編寫可能會出現(xiàn)異常的代碼 }catch(異常類型A e){ 當try中出現(xiàn)A類型異常,就用該catch來捕獲. 處理異常的代碼 //記錄日志/打印異常信息/繼續(xù)拋出異常 }catch(異常類型B e){ 當try中出現(xiàn)B類型異常,就用該catch來捕獲. 處理異常的代碼 //記錄日志/打印異常信息/繼續(xù)拋出異常 }
注意:這種異常處理方式,要求多個catch中的異常不能相同,并且若catch中的多個異常之間有子父類異常的關系,那么子類異常要求在上面的catch處理,父類異常在下面的catch處理。
運行時異常被拋出可以不處理。即不捕獲也不聲明拋出。
如果finally有return語句,永遠返回finally中的結果,避免該情況.
如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。
父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產(chǎn)生該異常,只能捕獲處理,不能聲明拋出
第三章 自定義異常 3.1 概述為什么需要自定義異常類:
我們說了Java中不同的異常類,分別表示著某一種具體的異常情況,那么在開發(fā)中總是有些異常情況是SUN沒有定義好的,此時我們根據(jù)自己業(yè)務的異常情況來定義異常類。例如年齡負數(shù)問題,考試成績負數(shù)問題等等。
在上述代碼中,發(fā)現(xiàn)這些異常都是JDK內部定義好的,但是實際開發(fā)中也會出現(xiàn)很多異常,這些異常很可能在JDK中沒有定義過,例如年齡負數(shù)問題,考試成績負數(shù)問題.那么能不能自己定義異常呢?
什么是自定義異常類:
在開發(fā)中根據(jù)自己業(yè)務的異常情況來定義異常類.
自定義一個業(yè)務邏輯異常: RegisterException。一個注冊異常類。
異常類如何定義:
自定義一個編譯期異常: 自定義類 并繼承于java.lang.Exception。
自定義一個運行時期的異常類:自定義類 并繼承于java.lang.RuntimeException。
3.2 自定義異常的練習要求:我們模擬注冊操作,如果用戶名已存在,則拋出異常并提示:親,該用戶名已經(jīng)被注冊。
首先定義一個登陸異常類RegisterException:
// 業(yè)務邏輯異常 public class RegisterException extends Exception { /** * 空參構造 */ public RegisterException() { } /** * * @param message 表示異常提示 */ public RegisterException(String message) { super(message); } }
模擬登陸操作,使用數(shù)組模擬數(shù)據(jù)庫中存儲的數(shù)據(jù),并提供當前注冊賬號是否存在方法用于判斷。
public class Demo { // 模擬數(shù)據(jù)庫中已存在賬號 private static String[] names = {"bill","hill","jill"}; public static void main(String[] args) { //調用方法 try{ // 可能出現(xiàn)異常的代碼 checkUsername("nill"); System.out.println("注冊成功");//如果沒有異常就是注冊成功 }catch(RegisterException e){ //處理異常 e.printStackTrace(); } } //判斷當前注冊賬號是否存在 //因為是編譯期異常,又想調用者去處理 所以聲明該異常 public static boolean checkUsername(String uname) throws LoginException{ for (String name : names) { if(name.equals(uname)){//如果名字在這里面 就拋出登陸異常 throw new RegisterException("親"+name+"已經(jīng)被注冊了!"); } } return true; } }第四章 多線程
我們在之前,學習的程序在沒有跳轉語句的前提下,都是由上至下依次執(zhí)行,那現(xiàn)在想要設計一個程序,邊打游戲邊聽歌,怎么設計?
要解決上述問題,咱們得使用多進程或者多線程來解決.
4.1 并發(fā)與并行并發(fā):指兩個或多個事件在同一個時間段內發(fā)生。
并行:指兩個或多個事件在同一時刻發(fā)生(同時發(fā)生)。
在操作系統(tǒng)中,安裝了多個程序,并發(fā)指的是在一段時間內宏觀上有多個程序同時運行,這在單 CPU 系統(tǒng)中,每一時刻只能有一道程序執(zhí)行,即微觀上這些程序是分時的交替運行,只不過是給人的感覺是同時運行,那是因為分時交替運行的時間是非常短的。
而在多個 CPU 系統(tǒng)中,則這些可以并發(fā)執(zhí)行的程序便可以分配到多個處理器上(CPU),實現(xiàn)多任務并行執(zhí)行,即利用每個處理器來處理一個可以并發(fā)執(zhí)行的程序,這樣多個程序便可以同時執(zhí)行。目前電腦市場上說的多核 CPU,便是多核處理器,核 越多,并行處理的程序越多,能大大的提高電腦運行的效率。
注意:單核處理器的計算機肯定是不能并行的處理多個任務的,只能是多個任務在單個CPU上并發(fā)運行。同理,線程也是一樣的,從宏觀角度上理解線程是并行運行的,但是從微觀角度上分析卻是串行運行的,即一個線程一個線程的去運行,當系統(tǒng)只有一個CPU時,線程會以某種順序執(zhí)行多個線程,我們把這種情況稱之為線程調度。4.2 線程與進程
進程:是指一個內存中運行的應用程序,每個進程都有一個獨立的內存空間,一個應用程序可以同時運行多個進程;進程也是程序的一次執(zhí)行過程,是系統(tǒng)運行程序的基本單位;系統(tǒng)運行一個程序即是一個進程從創(chuàng)建、運行到消亡的過程。
線程:線程是進程中的一個執(zhí)行單元,負責當前進程中程序的執(zhí)行,一個進程中至少有一個線程。一個進程中是可以有多個線程的,這個應用程序也可以稱之為多線程程序。
簡而言之:一個程序運行后至少有一個進程,一個進程中可以包含多個線程
我們可以再電腦底部任務欄,右鍵----->打開任務管理器,可以查看當前任務的進程:
進程
線程
線程調度:
分時調度
所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間。
搶占式調度
優(yōu)先讓優(yōu)先級高的線程使用 CPU,如果線程的優(yōu)先級相同,那么會隨機選擇一個(線程隨機性),Java使用的為搶占式調度。
設置線程的優(yōu)先級
搶占式調度詳解
大部分操作系統(tǒng)都支持多進程并發(fā)運行,現(xiàn)在的操作系統(tǒng)幾乎都支持同時運行多個程序。比如:現(xiàn)在我們上課一邊使用編輯器,一邊使用錄屏軟件,同時還開著畫圖板,dos窗口等軟件。此時,這些程序是在同時運行,”感覺這些軟件好像在同一時刻運行著“。
實際上,CPU(中央處理器)使用搶占式調度模式在多個線程間進行著高速的切換。對于CPU的一個核而言,某個時刻,只能執(zhí)行一個線程,而 CPU的在多個線程間切換速度相對我們的感覺要快,看上去就是在同一時刻運行。
其實,多線程程序并不能提高程序的運行速度,但能夠提高程序運行效率,讓CPU的使用率更高。
Java使用java.lang.Thread類代表線程,所有的線程對象都必須是Thread類或其子類的實例。每個線程的作用是完成一定的任務,實際上就是執(zhí)行一段程序流即一段順序執(zhí)行的代碼。Java使用線程執(zhí)行體來代表這段程序流。Java中通過繼承Thread類來創(chuàng)建并啟動多線程的步驟如下:
定義Thread類的子類,并重寫該類的run()方法,該run()方法的方法體就代表了線程需要完成的任務,因此把run()方法稱為線程執(zhí)行體。
創(chuàng)建Thread子類的實例,即創(chuàng)建了線程對象
調用線程對象的start()方法來啟動該線程
代碼如下:
測試類:
public class Demo01 { public static void main(String[] args) { //創(chuàng)建自定義線程對象 MyThread mt = new MyThread("新的線程!"); //開啟新線程 mt.start(); //在主方法中執(zhí)行for循環(huán) for (int i = 0; i < 10; i++) { System.out.println("main線程!"+i); } } }
自定義線程類:
public class MyThread extends Thread { //定義指定線程名稱的構造方法 public MyThread(String name) { //調用父類的String參數(shù)的構造方法,指定線程的名稱 super(name); } /** * 重寫run方法,完成該線程執(zhí)行的邏輯 */ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName()+":正在執(zhí)行!"+i); } } }
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75426.html
摘要:申明守護線程需要在開啟線程之前。線程池線程都是后臺線程。每個線程都使用默認的堆棧大小,以默認的優(yōu)先級運行,并處于多線程單元中。 創(chuàng)建線程 一個進程必有一個線程,進程也可由多個線程組成,但有一個線程為主線程。若一個任務需要花10Mins,當只有一個線程時,花費10Mins,當有十個線程時,可能就花費1Mins,所以多線程可以提升任務執(zhí)行時間,提高工作效率。python里與線程有關的模塊:...
摘要:中斷線程當線程的方法方法體執(zhí)行完畢自然終止或在方法中出現(xiàn)沒有捕獲的異常時意外終止,線程將終止。如果被中斷線程被阻塞,就無法檢測中斷狀態(tài),就會產(chǎn)生異常。 多進程與多線程的本質區(qū)別在于:每個進程擁有自己的一整套變量,而線程則共享數(shù)據(jù)。如果需要執(zhí)行一個比較耗時的任務,應該使用獨立的線程。 可以通過實現(xiàn)Runnable接口或繼承Thread類來創(chuàng)建獨立的線程。 1) 實現(xiàn)Ruannable接口...
摘要:使用雙檢查機制來實現(xiàn)多線程環(huán)境中的延遲加載單例設計模式。類主要負責日期的轉換與格式化,但在多線程環(huán)境中,使用此類容易造成數(shù)據(jù)轉換及處理的不準確,因為類并不是線程安全的。 立即加載就是使用類的時候已經(jīng)將對象創(chuàng)建完畢,常見的實現(xiàn)辦法就是直接new實例化。而立即加載從中文的語境來看,有著急、急迫的含義,所以也稱為餓漢模式。 package com.zxf.demo.singleton_0; ...
摘要:起因及介紹在處理原始對賬文件的時候,我將數(shù)據(jù)歸類后批量存入相應的表中。結論事務只能管著開啟事務的線程,其他子線程出了問題都感知不到,所以在多線程環(huán)境操作要慎重。高頻容易搞死服務器,低頻會阻塞自身程序。重試次數(shù)和超時時間根據(jù)業(yè)務情況設置。 起因及介紹 在處理原始對賬文件的時候,我將數(shù)據(jù)歸類后批量存入相應的表中。在持久化的時候,用了parallelStream(),想著同時存入很多表這樣可...
摘要:的多線程機制可彌補拋出未檢查的異常,將終止線程執(zhí)行,此時會錯誤的認為任務都取消了。如果想要不保留,則需要設置,此時最小的就是線程池最大的線程數(shù)。 提供Executor的工廠類showImg(https://segmentfault.com/img/bVbj3Ei?w=2890&h=1480); 忽略了自定義的ThreadFactory、callable和unconfigurable相關...
閱讀 1074·2021-11-16 11:45
閱讀 2708·2021-09-27 13:59
閱讀 1315·2021-08-31 09:38
閱讀 3143·2019-08-30 15:52
閱讀 1315·2019-08-29 13:46
閱讀 2085·2019-08-29 11:23
閱讀 1631·2019-08-26 13:47
閱讀 2476·2019-08-26 11:54