1. 程式人生 > 其它 >五、異常和執行緒

五、異常和執行緒

一、異常

java.lang.

  • Throwable:是所有錯誤或異常的超類

    • Error:錯誤

      錯誤相當於程式得了一個無法治癒的毛病,必須修改原始碼

    • Exception編譯期異常,進行編譯(寫程式碼)java程式出現的問題

      • RuntimeException:執行期異常,java程式執行過程中出現的問題

        異常相當於程式得了一個小毛病,把異常處理掉,程式可以繼續執行

JVM檢測程式會出現異常

JVM會做兩件事:JVM中斷處理

  1. JVM根據異常原因建立一個異常物件,包含內容,原因和位置

  2. 如果沒有異常處理邏輯(try...catch),JVM就會把異常丟擲給方法的呼叫者main方法

    main接收到這個異常物件,也沒有處理邏輯就丟擲給main方法的呼叫者JVM處理

    JVM接收到這個異常物件,做了兩件事1. 把異常物件以紅色字型列印在控制檯 2.終止現在正在執行的java程式

二、異常的處理

2.1 丟擲異常throw

throw關鍵字

作用:

​ 可以使用throw關鍵字在指定的方法中丟擲指定的異常

使用格式:

​ throw new xxxException("異常產生的原因")

注意:

  1. throw關鍵字必須寫在方法內部

  2. throw關鍵字後邊new的物件必須是Exception或者Exception的子類物件

  3. 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("產生原因");

}

注意:

  1. throws關鍵字必須寫在方法宣告處

  2. throws關鍵字後宣告的異常必須是Exception或者是Exception的子類

  3. 方法內部如果丟擲了多個異常物件,那麼throws後邊必須也宣告多個異常

    如果丟擲的多個異常物件有子父類關係,那麼直接宣告父類異常即可

    1. 呼叫了一個宣告丟擲異常的方法,我們就必須處理宣告的異常

    要麼繼續使用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中丟擲的異常物件){

​ 異常的處理邏輯,一般在工作中,會把異常資訊記錄到一個日誌中

​ }

注意:

  1. try中可能會丟擲多個異常,可以使用多個catch來處理

  2. 如果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程式碼塊

注意:

  1. finally不能單獨使用,必須和try一起使用
  2. finally一般用於資源釋放,無論程式是否異常,最後都要資源釋放(IO)

2.6 多異常捕獲處理

  1. 多異常分別處理

  2. 多異常一次捕獲,多次處理

    注意事項:

    catch裡面定義的異常變數,如果有子父類關係,那麼子類異常變數必須寫在上邊

  3. 多異常一次捕獲,一次處理

  • 執行期異常可以不捕獲也不處理 交給虛擬機器處理
  • 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類的子類

實現步驟:

  1. 建立一個Thread類的子類

  2. 在Thread的子類中重寫Thread類的run方法,設定執行緒任務

  3. 建立Thread的子類物件

  4. 呼叫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);
        }
    }
}