異常、多線程、try,catch,finall【總結】

一、異常
1.什麼是異常
異常就是不正常的情況。

2.異常的體系結構
    Throwable
        Error:大毛病。一般都是常見於:服務器宕機、數據庫服務器~~   簡單來說就是程序員無力解決
        Exception:小毛病。一般都是程序員所犯的小錯誤。例如:索引越界、空指針~~  簡單來說就是程序員可以解決的問題

3.異常的分類
    ☆編譯時異常:
        A:全部都是Exception的子類   ★★★
        B:當我們寫好代碼後編譯器直接報錯了,這個時候必須要經過處理纔可以去運行程序
    ☆運行時異常:
        A:全部都是RuntimeException的子類  ★★★
        B:當程序運行的時候纔會出現的問題
    錯誤:
        A:第一種情況,需要修改源代碼。重新思考解決問題的思路。
        B:第二種情況,程序員無力解決的問題。

4.Objects工具類的方法requireNonNull
    |--對數據進行合法性的判斷
        public class Demo04Objects {
            public static void main(String[] args) {
                method(null);
            }

            public static void method(Object obj){
                //對傳遞過來的參數進行合法性判斷,判斷是否爲null
                /*if(obj == null){
                    throw new NullPointerException("傳遞的對象的值是null");
                }*/

                //Objects.requireNonNull(obj);
                Objects.requireNonNull(obj,"傳遞的對象的值是null");
            }
        }
5.throw關鍵字
    作用:
        可以使用throw關鍵字在指定的方法中拋出指定的異常
            |--注意是在指定的方法中拋出指定的異常  ★★★
    使用格式:
        throw new xxxException("異常產生的原因");
    注意:
        1.throw關鍵字必須寫在方法的內部
        2.throw關鍵字後邊new的對象必須是Exception或者Exception的子類對象
        3.throw關鍵字拋出指定的異常對象,我們就必須處理這個異常對象
            |--throw關鍵字後邊創建的是RuntimeException或者是 RuntimeException的子類對象,
                我們可以不處理,默認交給JVM處理(打印異常對象,中斷程序)
            |--throw關鍵字後邊創建的是編譯異常(寫代碼的時候報錯),我們就必須處理這個異常,
                要麼throws,要麼try...catch
    ★★★清楚throw和throws的關係            
    示例代碼:
        public class Demo03Throw {
                public static void main(String[] args) {
                    //int[] arr = null;
                    int[] arr = new int[3];
                    int e = getElement(arr,3);
                    System.out.println(e);   //ArrayIndexOutOfBoundsException
                }
                /*
                定義一個方法,獲取數組指定索引處的元素
                參數:
                    int[] arr
                    int index
                以後(工作中)我們首先必須對方法傳遞過來的參數進行合法性校驗
                如果參數不合法,那麼我們就必須使用拋出異常的方式,告知方法的調用者,傳遞的參數有問題
                注意:
                    NullPointerException是一個運行期異常,我們不用處理,默認交給JVM處理
                    ArrayIndexOutOfBoundsException是一個運行期異常,我們不用處理,默認交給JVM處理
             */
                public static int getElement(int[] arr,int index){
                    /*
                        我們可以對傳遞過來的參數數組,進行合法性校驗
                        如果數組arr的值是null
                        那麼我們就拋出空指針異常,告知方法的調用者"傳遞的數組的值是null"
                     */
                    if(arr == null){
                        throw new NullPointerException("傳遞的數組的值是null");
                    }

                    /*
                        我們可以對傳遞過來的參數index進行合法性校驗
                        如果index的範圍不在數組的索引範圍內
                        那麼我們就拋出數組索引越界異常,告知方法的調用者"傳遞的索引超出了數組的使用範圍"
                     */
                    if(index<0 || index>arr.length-1){
                        throw new ArrayIndexOutOfBoundsException("傳遞的索引超出了數組的使用範圍");
                    }

                    int ele = arr[index];
                    return ele;    //合法性校驗沒有問題則返回原數組
                }
            }
6.第一種處理異常的方式
  |--拋出--|
    throws關鍵字:異常處理的第一種方式,交給別人處理
    作用:
        當方法內部拋出異常對象的時候,那麼我們就必須處理這個異常對象
        可以使用throws關鍵字處理異常對象,會把異常對象聲明拋出給方法的調用者處理(自己不處理,給別人處理),
        最終交給JVM處理-->中斷處理
    使用格式:在方法聲明時使用
            修飾符 返回值類型 方法名(參數列表) throws AAAExcepiton,BBBExcepiton...{
                throw new AAAExcepiton("產生原因");
                throw new BBBExcepiton("產生原因");
                ...
            }
     注意:
        1.throws關鍵字必須寫在方法聲明處
        2.throws關鍵字後邊聲明的異常必須是Exception或者是Exception的子類
        3.方法內部如果拋出了多個異常對象,那麼throws後邊必須也聲明多個異常
            如果拋出的多個異常對象有子父類關係,那麼直接聲明父類異常即可
        4.調用了一個聲明拋出異常的方法,我們就必須的處理聲明的異常
            要麼繼續使用throws聲明拋出,交給方法的調用者處理,最終交給JVM
            要麼try...catch自己處理異常
    示例代碼:
            public class Demo05Throws {
                /*
                    FileNotFoundException extends IOException extends Excepiton
                    如果拋出的多個異常對象有子父類關係,那麼直接聲明父類異常即可
                 */
                //public static void main(String[] args) throws FileNotFoundException,IOException {
                //public static void main(String[] args) throws IOException {
                public static void main(String[] args) throws Exception{
                    readFile("c:\\a.tx");

                    System.out.println("後續代碼");
                }

                /*
                    定義一個方法,對傳遞的文件路徑進行合法性判斷
                    如果路徑不是"c:\\a.txt",那麼我們就拋出文件找不到異常對象,告知方法的調用者
                    注意:
                        FileNotFoundException是編譯異常,拋出了編譯異常,就必須處理這個異常
                        可以使用throws繼續聲明拋出FileNotFoundException這個異常對象,讓方法的調用者處理
                 */
                public static void readFile(String fileName) throws Exception{
                    if(!fileName.equals("c:\\a.txt")){
                        throw new FileNotFoundException("傳遞的文件路徑不是c:\\a.txt");
                    }

                    /*
                        如果傳遞的路徑,不是.txt結尾
                        那麼我們就拋出IO異常對象,告知方法的調用者,文件的後綴名不對
                     */
                    if(!fileName.endsWith(".txt")){
                        throw new IOException("文件的後綴名不對");
                    }

                    System.out.println("路徑沒有問題,讀取文件");
                }
            }
7.第二種處理異常方式
      |--try...catch--|
        public class Demo01 {
            public static void main(String[] args)  {
                method2();
            }

            public static void method2()  {
                method();
            }

            public static void method()  {
                try{
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    Date d = sdf.parse("201807-25");   //這裏出現異常會執行下面的catch
                    System.out.println(d.toLocaleString());   //所以此句話不會輸出

                    System.out.println(2/0);    //不執行
                }catch(ParseException p) {
                    System.out.println("逗逼,趕快檢查一下parse方法中的字符串格式");
                }catch(ArithmeticException a) {
                    System.out.println("除數不能爲0");
                }

                System.out.println("1111111111111111");   //但是後面的代碼依然執行
            }
        }
8.Throwable類的常用方法
     String getMessage() 返回此 throwable 的簡短描述。
     String toString() 返回此 throwable 的詳細消息字符串。
     void printStackTrace()  JVM打印異常對象,默認此方法,打印的異常信息是最全面的

9.finally的使用
    |--不管程序有沒有發生異常,都會執行finally代碼塊,常用語IO、數據庫的資源釋放
    示例代碼:
        public class Demo02 {
            public static void main(String[] args) {
                try{
                    System.out.println("創建了數據庫的連接對象");  // ok
                    System.out.println(2/0);                      // 有問題
                    System.out.println("開始連接數據庫");
                    System.out.println("連接上了數據庫");
                }catch(ArithmeticException a) {
                    System.out.println("除數不能爲0");
                }finally {
                    System.out.println("釋放資源,關閉連接");
                }
            }
        }
10.多異常的處理和注意事項

public class Demo01Exception {
public static void main(String[] args) {
/*
多個異常使用捕獲又該如何處理呢?
1. 多個異常分別處理。
2. 多個異常一次捕獲,多次處理。
3. 多個異常一次捕獲一次處理。
*/

//1. 多個異常分別處理。
/*
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e);
}

try{
List list = List.of(1, 2, 3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (IndexOutOfBoundsException e){
System.out.println(e);
}
*/

//2. 多個異常一次捕獲,多次處理。
/*
try {
int[] arr = {1,2,3};
//System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
List list = List.of(1, 2, 3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e);
}catch (IndexOutOfBoundsException e){
System.out.println(e);
}
*/

/*
一個try多個catch注意事項:
catch裏邊定義的異常變量,如果有子父類關係,那麼子類的異常變量必須寫在上邊,否則就會報錯★★★★★
ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException
*/
★★★★★
/*
try {
int[] arr = {1,2,3};
//System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
List list = List.of(1, 2, 3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (IndexOutOfBoundsException e){ //這個catch裏面的異常時是下面catch裏面異常的子類
System.out.println(e);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e);
}
*/

//3. 多個異常一次捕獲一次處理。(太過於籠統,後面catch不確定給出拋出異常的信息)
/*
try {
int[] arr = {1,2,3};
System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
List list = List.of(1, 2, 3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
}catch (Exception e){
System.out.println(e);
}
*/

//運行時異常被拋出可以不處理。即不捕獲也不聲明拋出。
//默認給虛擬機處理,終止程序,什麼時候不拋出運行時異常了,在來繼續執行程序
int[] arr = {1,2,3};
System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
List list = List.of(1, 2, 3);
System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3

System.out.println(“後續代碼!”);
}
}
11.finally代碼塊中是否可以有return語句

        /*
            如果finally有return語句,永遠返回finally中的結果,避免該情況.
         */
        public class Demo02Exception {
            public static void main(String[] args) {
                int a = getA();
                System.out.println(a);
            }

            //定義一個方法,返回變量a的值
            public static int getA(){
                int a = 10;
                try{
                    return a;
                }catch (Exception e){
                    System.out.println(e);
                }finally {
                    //一定會執行的代碼
                    a = 100;
                    return a;
                }
            }
        }
12.子父類關係方法重寫時異常的聲明情況
/*
            子父類的異常:
                - 如果父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異常。
                - 父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。此時子類產生該異常,只能捕獲處理,不能聲明拋出
            注意:
                父類異常時什麼樣,子類異常就什麼樣
         */
        public class Fu {
            public void show01() throws NullPointerException,ClassCastException{}
            public void show02() throws IndexOutOfBoundsException{}
            public void show03() throws IndexOutOfBoundsException{}
            public void show04() {}
        }

        class Zi extends Fu{
            //子類重寫父類方法時,拋出和父類相同的異常
            public void show01() throws NullPointerException,ClassCastException{}
            //子類重寫父類方法時,拋出父類異常的子類
            public void show02() throws ArrayIndexOutOfBoundsException{}
            //子類重寫父類方法時,不拋出異常
            public void show03() {}

            /*
                父類方法沒有拋出異常,子類重寫父類該方法時也不可拋出異常。
             */
            //public void show04() throws Exception{}

            //此時子類產生該異常,只能捕獲處理,不能聲明拋出
            public void show04() /*throws ParseException*/ {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    Date parse = sdf.parse("5555");
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }
13.自定義異常
    public class RegisterException extends /*Exception*/ RuntimeException{
            //添加一個空參數的構造方法
            public RegisterException(){
                super();
            }

            /*
                添加一個帶異常信息的構造方法
                查看源碼發現,所有的異常類都會有一個帶異常信息的構造方法,
                方法內部會調用父類帶異常信息的構造方法,讓父類來處理這個異常信息
             */
            public RegisterException(String message){
                super(message);
            }
        }

        //測試類
        public class Demo02RegisterException {
            // 1.使用數組保存已經註冊過的用戶名(數據庫)
            static String[] usernames = {"張三","李四","王五"};

            public static void main(String[] args) /*throws RegisterException*/{
                //2.使用Scanner獲取用戶輸入的註冊的用戶名(前端,頁面)
                Scanner sc = new Scanner(System.in);
                System.out.println("請輸入您要註冊的用戶名:");
                String username = sc.next();
                checkUsername(username);

            }
        //3.定義一個方法,對用戶輸入的中註冊的用戶名進行判斷
            public static void checkUsername(String username) /*throws RegisterException*/ {
                //遍歷存儲已經註冊過用戶名的數組,獲取每一個用戶名
                for (String name : usernames) {
                    //使用獲取到的用戶名和用戶輸入的用戶名比較
                    if(name.equals(username)){
                        //true:用戶名已經存在,拋出RegisterException異常,告知用戶"親,該用戶名已經被註冊";
                        try {
                            //拋出運行期異常,無需處理,交給JVM處理,中斷處理 
                            throw new RegisterException("親,該用戶名已經被註冊");
                        } catch (RegisterException e) {
                            e.printStackTrace();
                            //return;
                        }
                    }
                }

                //如果循環結束了,還沒有找到重複的用戶名,提示用戶"恭喜您,註冊成功!";
                System.out.println("恭喜您,註冊成功!");
            }
        }

二、多線程
1.什麼是併發和並行
併發就是在同一段時間內交替執行多個任務,交替運行
並行就是在同一段時間內同時執行多個任務,同時運行

2.什麼是進程
    指的就是一個軟件在運行期間,在內存中的一個執行區域

3.什麼是線程
    指的就是在一個進程中包含多個執行任務,每一個任務就是一個線程

4.如何開啓一個多線程
一、創建一個類繼承Thread
    示例代碼1:
        現在商家有有100袋堅果,分別分爲實體店售出和官網售出
        創建兩個線程一個表示官網、一個表示實體店
        賣完爲止
        //線程類
        public class MyThread extends Thread {
            public static int num = 100;  //100份堅果
            public static int count = 1;

            private String name;     //商家名稱

            MyThread(String name) {
                this.name = name;
            }

            @Override
            public void run() {
                while (num > 0) {
                    System.out.println(name + "正在賣出第" + (count++) + "份" + ",還剩下" + --num + " 份");
                }
            }
        }
        //測試類
        public class Main {
            public static void main(String[] args) {
                MyThread my1 = new MyThread("官網");
                MyThread my2 = new MyThread("實體店");
                my1.start();
                my2.start();
            }
        }
二、請使用繼承Thread類的方式開啓兩個線程
    (1)第一個線程的名字設置爲:a   第二個線程的名字設置爲:b
    (2)第一個線程裏面實現計算1+2+3+4+....+100的和
    (3)第二個線程裏面實現計算1+2+3+4+....+200的和
    程序最終打印結果:
            a:5050
            b:20100   (a和b的打印順序不作要求)
        //線程類
        public class MyThread extends Thread {

            @Override
            public void run() {
                int a = 0;
                int b = 0;
                if(getName().equals("a"))
                {
                    for(int i = 1 ; i <= 100 ;i++)
                    {
                        a = a +i;
                    }
                    System.out.println(getName() + ":" + a);
                }
                if(getName().equals("b"))
                {
                    for(int i = 1 ;i <= 200 ;i++)
                    {
                        b = b +i;
                    }
                    System.out.println(getName() + ":" + b);
                }
            }
            /* 第二實現方式*/
            /*
                @Override
                public void run() {
                    while (true) {
                        if (getName().equals("a")) {
                            if (a1 < 100) {
                                sumA = sumA + (++a1);
                            }
                            else {
                                System.out.println(getName() + ":" + sumA); break;
                            }
                        }
                        if (getName().equals("b")) {
                            if (b1 < 200) {
                                sumB = sumB + (++b1);
                            } else {
                                System.out.println(getName() + ":" + sumB);break;
                            }
                        }

                    }
                }
            */
        }
        //測試類
        public class StartThread {
            public static void main(String[] args) {
                MyThread my1 = new MyThread();
                my1.setName("a");
                my1.run();
                MyThread my2 = new MyThread();
                my2.setName("b");
                my2.run();
            }
        }
發佈了97 篇原創文章 · 獲贊 23 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章