五、異常和執行緒
一、異常
java.lang.
-
Throwable:是所有錯誤或異常的超類
-
Error:錯誤
錯誤相當於程式得了一個無法治癒的毛病,必須修改原始碼
-
Exception編譯期異常,進行編譯(寫程式碼)java程式出現的問題
-
RuntimeException:執行期異常,java程式執行過程中出現的問題
異常相當於程式得了一個小毛病,把異常處理掉,程式可以繼續執行
-
-
JVM檢測程式會出現異常
JVM會做兩件事:JVM中斷處理
-
JVM根據異常原因建立一個異常物件,包含內容,原因和位置
-
如果沒有異常處理邏輯(try...catch),JVM就會把異常丟擲給方法的呼叫者main方法
main接收到這個異常物件,也沒有處理邏輯就丟擲給main方法的呼叫者JVM處理
JVM接收到這個異常物件,做了兩件事1. 把異常物件以紅色字型列印在控制檯 2.終止現在正在執行的java程式
二、異常的處理
2.1 丟擲異常throw
throw關鍵字
作用:
可以使用throw關鍵字在指定的方法中丟擲指定的異常
使用格式:
throw new xxxException("異常產生的原因")
注意:
-
throw關鍵字必須寫在方法內部
-
throw關鍵字後邊new的物件必須是Exception或者Exception的子類物件
-
throw關鍵字丟擲指定的異常物件,我們必須處理這個異常物件
throw關鍵字後面建立的是RuntimeException或者是RuntimeException的子類物件,我們可以不處理,預設交給JVM處理
throw關鍵字後面建立的是編譯異常,我們就必須處理這個異常,要麼throws要麼try...catch
throw new NullPointerException("傳遞物件為null");
2.2 Objects非空判斷
Object obj = null;
Objects.requireNonNull(obj,"傳遞的物件為null");
2.3 宣告異常throws
異常處理的第一種方式,交給別人處理
作用:
當方法內部丟擲異常物件的時候,必須處理這個異常物件
可以使用throws處理異常,把異常物件交給呼叫者處理,JVM-->中斷處理
使用格式:在方法宣告時使用
修飾符 返回值型別 方法名(引數列表)throws XXXException,...{
throw new XXXException("產生原因");
}
注意:
-
throws關鍵字必須寫在方法宣告處
-
throws關鍵字後宣告的異常必須是Exception或者是Exception的子類
-
方法內部如果丟擲了多個異常物件,那麼throws後邊必須也宣告多個異常
如果丟擲的多個異常物件有子父類關係,那麼直接宣告父類異常即可
- 呼叫了一個宣告丟擲異常的方法,我們就必須處理宣告的異常
要麼繼續使用throws丟擲,交給方法呼叫者處理,最終交給JVM
要麼try...catch
public class Demo01Throwable {
public static void main(String[] args) throws IOException {
readFile("c://a.txt");
}
public static void readFile(String fileName) throws IOException {
if (!fileName.equals("c://a.txt")){
throw new FileNotFoundException("檔案路徑異常");
}
if (!fileName.endsWith(".txt")){
throw new IOException("檔案的字尾名異常");
}
}
}
2.4 捕獲異常try catch
try...catch:異常處理的第二種方式,自己處理異常
格式:
try{
}catch(定義一個異常的變數,用來接收try中丟擲的異常物件){
異常的處理邏輯,一般在工作中,會把異常資訊記錄到一個日誌中
}
注意:
-
try中可能會丟擲多個異常,可以使用多個catch來處理
-
如果try中產生了異常,就會執行catch中的異常處理邏輯,執行完catch中的處理邏輯,就會執行之後的程式碼
如果try沒有產生異常,就不會執行catch中異常處理邏輯,執行完try中的程式碼,繼續執行try...catch後的程式碼
public class Demo01Throwable {
public static void main(String[] args){
try {
readFile("c://a.xt");
} catch (IOException e) {
System.out.println("catch.檔案字尾不是.txt");
}
System.out.println("後續程式碼");
}
public static void readFile(String fileName) throws IOException {
if (!fileName.endsWith(".txt")){
throw new IOException("檔案的字尾名異常");
}
}
}
Throwable類中定義了3個異常處理的方法
-
String getMessage()
返回throwable的簡短描述 -
String toString()
返回throwable的詳細資訊字串 -
void printStackTrace(PrintStream s)
JVM列印異常物件,預設此方法,異常資訊最全面
2.5 finally程式碼塊
注意:
- finally不能單獨使用,必須和try一起使用
- finally一般用於資源釋放,無論程式是否異常,最後都要資源釋放(IO)
2.6 多異常捕獲處理
-
多異常分別處理
-
多異常一次捕獲,多次處理
注意事項:
catch裡面定義的異常變數,如果有子父類關係,那麼子類異常變數必須寫在上邊
-
多異常一次捕獲,一次處理
- 執行期異常可以不捕獲也不處理 交給虛擬機器處理
- finally中有return語句,永遠返回finally的結果,避免該情況
- 如果父類丟擲了多個異常,子類重寫父類方法時,丟擲和父類相同的異常或者父類異常的子類或者不丟擲異常
- 父類方法沒有丟擲異常,子類重寫父類方法時,也不能丟擲異常,只能捕獲處理
三、 自定義異常
自定義異常類:
java提供異常類,不夠我們使用,需要自己定義一些異常類
格式:
public class XXXException extends Exception / RuntimeException{
新增一個空引數的構造方法
新增一個帶異常資訊的構造方法
}
注意:
1. 自定義異常類一般都是以Exception結尾,說明該類是一個異常類
2. 自定義異常類,必須繼承Exception或者RuntimeException
1. 繼承Exception,那麼自定義異常類是一個編譯期異常,如果方法內部丟擲了編譯期異常,就必須處理這個異常,要麼throws,要麼try catch
2. 繼承RuntimeException,那麼自定義異常類是一個執行期異常,無需處理,交給虛擬機器處理(中斷處理
1.繼承Exception
public class MyException extends Exception {
public MyException(){
super();
}
public MyException(String s){
super(s);
}
}
public class Demo01Throwable {
//1.使用資料儲存已經註冊的使用者名稱
static String[] userNames={"張三","李四","王五"};
//寫在成員位置 方便都訪問的到
public static void main(String[] args) /*throws MyException*/ {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入您要註冊的使用者名稱:");
String userName = scanner.next();
checkUserName(userName);
}
public static void checkUserName(String usrname) /*throws MyException*/ {
for (String userName : userNames) {
if (usrname.contains(userName)){
//true
try {
throw new MyException("該使用者已經被註冊了");
} catch (MyException e) {
e.printStackTrace();
return;//結束方法
}
}
}
System.out.println("恭喜您,註冊成功");
}
}
2.繼承RuntimeException
package com.dy.test;
public class MyException extends /*Exception*/ RuntimeException{
public MyException(){
super();
}
public MyException(String s){
super(s);
}
}
public class Demo02Throwable {
//1.使用資料儲存已經註冊的使用者名稱
static String[] userNames={"張三","李四","王五"};
//寫在成員位置 方便都訪問的到
public static void main(String[] args) /*throws MyException*/ {
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入您要註冊的使用者名稱:");
String userName = scanner.next();
checkUserName(userName);
}
public static void checkUserName(String usrname) /*throws MyException*/ {
for (String userName : userNames) {
if (usrname.contains(userName)){
//true
throw new MyException("該使用者已經被註冊了");//丟擲執行期異常 無需處理 交給JVM處理 中斷處理
}
}
System.out.println("恭喜您,註冊成功");
}
}
四、多執行緒
4.1 併發與並行
併發:兩個或多個事件在同一時間段內發生。cpu交替執行
並行:兩個或多個事件在同一時刻發生(同時發生)。cpu同時執行
4.2 執行緒與程序
記憶體:所有應用程式都要進入到記憶體中執行 臨時儲存RAM
硬碟:永久儲存ROM
點選應用程式執行,進入到記憶體中,佔用一些記憶體執行,進入到記憶體的程式叫做程序
工作管理員-->結束程序
那麼就把程序從記憶體中清除了
cpu:中央處理器,對資料進行計算,指揮電腦中的軟體和硬體幹活
cpu的分類:
AMD:
Inter:
執行緒是程序中的一個執行單元,負責程式的執行。
一個程式至少有一個程序,一個程序中包含多個執行緒
執行緒排程:
分時排程:
平均分配佔用時間
搶佔式排程:
優先順序
4.3 建立執行緒類
單執行緒
主執行緒:執行主方法(main)的執行緒
單執行緒程式:java程式中只有一個執行緒
執行從main方法開始,從上到下依次執行
JVM執行main方法,main方法會進入到棧記憶體
JVM會找作業系統開闢一條main方法到cpu的執行路徑
cpu就可以通過這個路徑來執行main方法
而這個路徑叫main(主)執行緒
public class Demo01MainThread {
public static void main(String[] args) {
Person p1 = new Person("小紅");
p1.run();
Person p2 = new Person("小綠");
p2.run();
}
}
public class Person {
private String name;
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(name+"-->"+i);
}
}
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
多執行緒
建立多執行緒程式的第一種方式:建立Thread類的子類
實現步驟:
-
建立一個Thread類的子類
-
在Thread的子類中重寫Thread類的run方法,設定執行緒任務
-
建立Thread的子類物件
-
呼叫Thread類中的方法start()方法,開啟新的執行緒,執行run方法
start()導致此執行緒開始執行;Java虛擬機器呼叫此執行緒的
run
方法。結果是兩個執行緒同時執行:當前執行緒(從呼叫返回到
start
方法)和另一個執行緒(執行其run
方法)。不止一次啟動執行緒是不合法的。 特別地,一旦執行緒完成執行就可能不會重新啟動。
public class Demo01Thread {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 20; i++) {
System.out.println("main:"+i);
}
}
}
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run:"+i);
}
}
}