欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 知識(shí)難點(diǎn)之異常的認(rèn)知與使用詳解

 更新時(shí)間:2021年09月26日 09:53:42   作者:意愿三七  
所謂異常是指程序在運(yùn)行時(shí)出現(xiàn)錯(cuò)誤時(shí)提示調(diào)用者的機(jī)制,異常的種類(lèi)有很多,不同種類(lèi)的異常有不同的含義,也有不同的處理方式,通讀本篇對(duì)大家的學(xué)習(xí)或工作具有一定的價(jià)值,需要的朋友可以參考下

前言

本篇文章你會(huì)學(xué)習(xí)到什么是異常,異常的基本語(yǔ)法使用,和自定義異常,干貨多多?。。?/p>

在這里插入圖片描述

一、 異常的背景

初識(shí)異常

我們?cè)?jīng)的代碼中已經(jīng)接觸了一些 “異常” 了. 例如

除以 0

public static void main(String[] args) {
        System.out.println(10 / 0);
    }

算術(shù)異常:

在這里插入圖片描述

數(shù)組下標(biāo)越界

數(shù)組越界

int[] arr = {1, 2, 3};
System.out.println(arr[100]);
// 執(zhí)行結(jié)果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100

訪問(wèn) null 對(duì)象

空指針異常

public class Test {
    public int num = 10;
    public static void main(String[] args) {
        Test t = null;
        System.out.println(t.num);
   }
}
// 執(zhí)行結(jié)果
Exception in thread "main" java.lang.NullPointerException

異常分為2種:

運(yùn)行時(shí)異常(非受查異常)

  • 算數(shù)異常 數(shù)組越界異常 空指針異常 都是程序運(yùn)行的過(guò)程當(dāng)中發(fā)生的異常

編譯時(shí)異常(受查異常)

  • 比如使用clone方法 在編譯前就劃紅線了就是編譯時(shí)異常

在這里插入圖片描述

異常體系:

在這里插入圖片描述

我們來(lái)看一下空指針異常(其實(shí)是一個(gè)類(lèi)繼承了運(yùn)行時(shí)異常)

在這里插入圖片描述

對(duì)應(yīng)上面的圖,

在看一下運(yùn)行時(shí)異常:繼承了Exception(也可以看上面的圖)

在這里插入圖片描述

看一下Exception 繼承了Throwable:

在這里插入圖片描述

通過(guò)這個(gè)圖我們得到一個(gè)結(jié)論:每一個(gè)異常都是一個(gè)類(lèi),異常之間的關(guān)系 參考圖上繼承

我們看看Error

在這里插入圖片描述

這個(gè)就叫做錯(cuò)誤

在這里插入圖片描述

異常和錯(cuò)誤的區(qū)別:

錯(cuò)誤:必須由程序員處理邏輯錯(cuò)誤
異常:處理異常就OK了接下來(lái)繼續(xù)看

防御式編程:

錯(cuò)誤在代碼中是客觀存在的. 因此我們要讓程序出現(xiàn)問(wèn)題的時(shí)候及時(shí)通知程序猿. 我們有兩種主要的方式
LBYL: Look Before You Leap. 在操作之前就做充分的檢查.

EAFP: It's Easier to Ask Forgiveness than Permission. “事后獲取原諒比事前獲取許可更容易”. 也就是先操作, 遇到問(wèn)題再處理.

注意!!! 上面這兩個(gè)概念千萬(wàn)不要背!
其實(shí)很好理解, 舉個(gè)栗子~~
比如老濕年輕的時(shí)候, 和你們師娘剛開(kāi)始談對(duì)象. 我們都知道, 談對(duì)象需要有一些親密的動(dòng)作, 比如 “拉小手” 這 種. emmmmm 問(wèn)題來(lái)了, 老濕去拉師娘的小手有兩種方式:

a) 老濕說(shuō), 妹子, 我拉你小手可以嘛? 獲取妹子的同意后, 再拉手(這就是 LBYL).

b) 老濕趁妹子不備, 直接拉住. 大不了妹子生氣了給老濕一巴掌, 老濕再道歉就是(這就是 EAFP).

異常的核心思想就是 EAFP.

異常的好處

例如, 我們用偽代碼演示一下開(kāi)始一局王者榮耀的過(guò)程.

LBYL 風(fēng)格的代碼(不使用異常)

boolean ret = false;
ret = 登陸游戲();
if (!ret) {
 處理登陸游戲錯(cuò)誤;
    return; }
ret = 開(kāi)始匹配();
if (!ret) {
 處理匹配錯(cuò)誤;
    return; }
ret = 游戲確認(rèn)();
if (!ret) {
 處理游戲確認(rèn)錯(cuò)誤;
    return; }
ret = 選擇英雄();
if (!ret) {
    處理選擇英雄錯(cuò)誤;
    return; }
ret = 載入游戲畫(huà)面();
if (!ret) {
 處理載入游戲錯(cuò)誤;
    return; }

EAFP 風(fēng)格的代碼(使用異常)

try {
    登陸游戲();
    開(kāi)始匹配();
    游戲確認(rèn)();
    選擇英雄();
    載入游戲畫(huà)面();
   ...
} catch (登陸游戲異常) {
    處理登陸游戲異常;
} catch (開(kāi)始匹配異常) {
 處理開(kāi)始匹配異常;
} catch (游戲確認(rèn)異常) {
 處理游戲確認(rèn)異常;
} catch (選擇英雄異常) {
 處理選擇英雄異常;
} catch (載入游戲畫(huà)面異常) {
 處理載入游戲畫(huà)面異常; }

對(duì)比兩種不同風(fēng)格的代碼, 我們可以發(fā)現(xiàn), 使用第一種方式, 正常流程和錯(cuò)誤處理流程代碼混在一起, 代碼整體顯的比較混亂. 而第二種方式正常流程和錯(cuò)誤流程是分離開(kāi)的, 更容易理解代碼

二、異常的基本用法

基本語(yǔ)法

在這里插入圖片描述

  • try 代碼塊中放的是可能出現(xiàn)異常的代碼.
  • catch 代碼塊中放的是出現(xiàn)異常后的處理行為.
  • finally 代碼塊中的代碼用于處理善后工作, 會(huì)在最后執(zhí)行.
  • 其中 catch 和 finally 都可以根據(jù)情況選擇加或者不加.

代碼:

public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        System.out.println("before");
        System.out.println(arr[100]);
        System.out.println("after");
    }

在這里插入圖片描述

解釋?zhuān)?/p>

在這里插入圖片描述

我們發(fā)現(xiàn)一旦出現(xiàn)異常, 程序就終止了. after 沒(méi)有正確輸出

為什么?

當(dāng)沒(méi)有處理異常的時(shí)候一旦程序發(fā)生了異常之后,這個(gè)異常會(huì)交給jvm,如果給jvm處理異常,那么程序一定會(huì)終止。

我們來(lái)自己處理異常:catch一定要捕獲相應(yīng)的異常(沒(méi)有捕獲到就交給了JVM了)

在這里插入圖片描述

結(jié)果:

在這里插入圖片描述

但是下面的也不會(huì)執(zhí)行了

在這里插入圖片描述

相比上面的我們處理了異常,讓程序可以繼續(xù)運(yùn)行下去了

那上面是沒(méi)有異常消息的提示了,我們還想要些提示怎么搞呢??

使用:e.printStackTrace(); after還是正常出來(lái)

在這里插入圖片描述

這個(gè)紅字可以進(jìn)行參考。

代碼示例 catch 可以有多個(gè):

在這里插入圖片描述

一段代碼可能會(huì)拋出多種不同的異常, 不同的異常有不同的處理方式. 因此可以搭配多個(gè) catch 代碼塊.
如果多個(gè)異常的處理方式是完全相同, 也可以寫(xiě)成這樣

代碼示例 也可以用一個(gè) catch 捕獲所有異常(不推薦)

int[] arr = {1, 2, 3};
try {
    System.out.println("before");
    arr = null;
    System.out.println(arr[100]);
    System.out.println("after");
} catch (Exception e) {
    e.printStackTrace();
}
System.out.println("after try catch");

為什么不推薦了,因?yàn)閑xception 范圍太大了,不好排查

代碼示例 finally 的執(zhí)行不需要條件

int[] arr = {1, 2, 3};
try {
    System.out.println("before");
    arr = null;
    System.out.println(arr[100]);
    System.out.println("after");
} catch (Exception e) {
    e.printStackTrace();
} finally {
    System.out.println("finally code");
}

在這里插入圖片描述

finally 無(wú)論有沒(méi)有異常都會(huì)最后執(zhí)行

代碼示例 使用 try 負(fù)責(zé)回收資源

Scanner.close()可以釋放資源可以寫(xiě)到finally里面,也可以直接寫(xiě)到try里面

try (Scanner sc = new Scanner(System.in)) {
    int num = sc.nextInt();
    System.out.println("num = " + num);
} catch (Exception e) {
    e.printStackTrace();
}

代碼示例 如果向上一直傳遞都沒(méi)有合適的方法處理異常, 最終就會(huì)交給 JVM 處理, 程序就會(huì)異常終止(和我們最開(kāi)始未使用 try catch 時(shí)是一樣的).

public static void main(String[] args) {
    try {
        func();
   } catch (ArrayIndexOutOfBoundsException e) {
        e.printStackTrace();
   }
    System.out.println("after try catch");
}
public static void func() {
    int[] arr = {1, 2, 3};
    System.out.println(arr[100]);
}
// 直接結(jié)果
java.lang.ArrayIndexOutOfBoundsException: 100
 at demo02.Test.func(Test.java:18)
 at demo02.Test.main(Test.java:9)
after try catch

可以看見(jiàn)上面代碼是func可以有異常,但是在main方法里面處理了的

異常處理流程

  • 程序先執(zhí)行 try 中的代碼
  • 如果 try 中的代碼出現(xiàn)異常, 就會(huì)結(jié)束 try 中的代碼, 看和 catch 中的異常類(lèi)型是否匹配.
  • 如果找到匹配的異常類(lèi)型, 就會(huì)執(zhí)行 catch 中的代碼
  • 如果沒(méi)有找到匹配的異常類(lèi)型, 就會(huì)將異常向上傳遞到上層調(diào)用者.
  • 無(wú)論是否找到匹配的異常類(lèi)型, finally 中的代碼都會(huì)被執(zhí)行到(在該方法結(jié)束之前執(zhí)行).
  • 如果上層調(diào)用者也沒(méi)有處理的了異常, 就繼續(xù)向上傳遞.
  • 一直到 main 方法也沒(méi)有合適的代碼處理異常, 就會(huì)交給 JVM 來(lái)進(jìn)行處理, 此時(shí)程序就會(huì)異常終止.

關(guān)于異常的處理方式

異常的種類(lèi)有很多, 我們要根據(jù)不同的業(yè)務(wù)場(chǎng)景來(lái)決定.

對(duì)于比較嚴(yán)重的問(wèn)題(例如和算錢(qián)相關(guān)的場(chǎng)景), 應(yīng)該讓程序直接崩潰, 防止造成更嚴(yán)重的后果

對(duì)于不太嚴(yán)重的問(wèn)題(大多數(shù)場(chǎng)景), 可以記錄錯(cuò)誤日志, 并通過(guò)監(jiān)控報(bào)警程序及時(shí)通知程序猿

對(duì)于可能會(huì)恢復(fù)的問(wèn)題(和網(wǎng)絡(luò)相關(guān)的場(chǎng)景), 可以嘗試進(jìn)行重試.

在我們當(dāng)前的代碼中采取的是經(jīng)過(guò)簡(jiǎn)化的第二種方式. 我們記錄的錯(cuò)誤日志是出現(xiàn)異常的方法調(diào)用信息, 能很快

速的讓我們找到出現(xiàn)異常的位置. 以后在實(shí)際工作中我們會(huì)采取更完備的方式來(lái)記錄異常信息

拋出異常

除了 Java 內(nèi)置的類(lèi)會(huì)拋出一些異常之外, 程序猿也可以手動(dòng)拋出某個(gè)異常. 使用 throw 關(guān)鍵字完成這個(gè)操作

public static void main(String[] args) { 
 System.out.println(divide(10, 0)); 
} 
public static int divide(int x, int y) { 
 if (y == 0) { 
 throw new ArithmeticException("拋出除 0 異常"); 
 } 
 return x / y; 
} 
// 執(zhí)行結(jié)果
Exception in thread "main" java.lang.ArithmeticException: 拋出除 0 異常
 at demo02.Test.divide(Test.java:14) 
 at demo02.Test.main(Test.java:9)

在這個(gè)代碼中, 我們可以根據(jù)實(shí)際情況來(lái)拋出需要的異常. 在構(gòu)造異常對(duì)象同時(shí)可以指定一些描述性信息.

異常說(shuō)明
我們?cè)谔幚懋惓5臅r(shí)候, 通常希望知道這段代碼中究竟會(huì)出現(xiàn)哪些可能的異常.

我們可以使用 throws 關(guān)鍵字, 把可能拋出的異常顯式的標(biāo)注在方法定義的位置. 從而提醒調(diào)用者要注意捕獲這些異常.

public static int divide(int x, int y) throws ArithmeticException { 
 if (y == 0) { 
 throw new ArithmeticException("拋出除 0 異常"); 
 } 
 return x / y; 
}

三、 自定義異常類(lèi)

Java 中雖然已經(jīng)內(nèi)置了豐富的異常類(lèi), 但是我們實(shí)際場(chǎng)景中可能還有一些情況需要我們對(duì)異常類(lèi)進(jìn)行擴(kuò)展, 創(chuàng)建符合我們實(shí)際情況的異常.

我們先看一下其他的異常大概是個(gè)怎么樣的一個(gè)體系:

在這里插入圖片描述

空指針異常是繼承了個(gè)運(yùn)行時(shí)異常,不過(guò)他里面的方法寫(xiě)的不是很多,也就是兩個(gè)幫父類(lèi)的構(gòu)造方法,所以按照它這樣的我們也可以寫(xiě)一個(gè)自己的異常。

創(chuàng)建一個(gè)異常類(lèi):

在這里插入圖片描述

使用:

在這里插入圖片描述

結(jié)果:

在這里插入圖片描述

以上就是我們的一個(gè)自定義異常

那么我們可不可以繼承Exception呢?

在這里插入圖片描述

這里發(fā)現(xiàn)報(bào)錯(cuò)了,為什么?我們?cè)趤?lái)看一下異常體系結(jié)構(gòu)

在這里插入圖片描述

這個(gè)時(shí)候編譯器不知道是編譯時(shí)異常還是運(yùn)行時(shí)異常,所以默認(rèn)選擇權(quán)限小的編譯時(shí)異常,這個(gè)時(shí)候我們要拋出異常

在這里插入圖片描述

上面的沒(méi)有報(bào)錯(cuò)了下面的開(kāi)始了?為什么?因?yàn)槲覀儝伋鼍幾g時(shí)異常,我們要try catch一下:

在這里插入圖片描述

所以這個(gè)就是一個(gè)自定義異常。

在舉一個(gè)例子:

例如, 我們實(shí)現(xiàn)一個(gè)用戶登陸功能:(如果用戶名錯(cuò)誤處理用戶名的錯(cuò)誤,密碼錯(cuò)誤處理密碼錯(cuò)誤)

在這里插入圖片描述

此時(shí)我們?cè)谔幚碛脩裘艽a錯(cuò)誤的時(shí)候可能就需要拋出兩種異常. 我們可以基于已有的異常類(lèi)進(jìn)行擴(kuò)展(繼承), 創(chuàng)建和我們業(yè)務(wù)相關(guān)的異常類(lèi)

在這里插入圖片描述

自己寫(xiě)的類(lèi)

我們可以在login里面這樣寫(xiě):

在這里插入圖片描述

主方法:

在這里插入圖片描述

這樣就是使用我們自己的異常。

注意事項(xiàng):

  • 自定義異常通常會(huì)繼承自 Exception 或者 RuntimeException
  • 繼承自 Exception 的異常默認(rèn)是受查異常
  • 繼承自 RuntimeException 的異常默認(rèn)是非受查異常.

以上就是異常的全部?jī)?nèi)容了,如果有什么不對(duì)的地方歡迎評(píng)論指正謝謝??!

到此這篇關(guān)于Java 知識(shí)難點(diǎn)之異常的認(rèn)知與使用詳解的文章就介紹到這了,更多相關(guān)Java 異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)洗牌發(fā)牌的方法

    Java實(shí)現(xiàn)洗牌發(fā)牌的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)洗牌發(fā)牌的方法,涉及java針對(duì)數(shù)組的遍歷與排序操作相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • Java中字符串轉(zhuǎn)int數(shù)據(jù)類(lèi)型的三種方式

    Java中字符串轉(zhuǎn)int數(shù)據(jù)類(lèi)型的三種方式

    這篇文章主要介紹了Java中字符串轉(zhuǎn)int數(shù)據(jù)類(lèi)型的三種方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • 在SpringBoot項(xiàng)目中解決依賴沖突問(wèn)題的方法

    在SpringBoot項(xiàng)目中解決依賴沖突問(wèn)題的方法

    在SpringBoot項(xiàng)目中,依賴沖突是一個(gè)常見(jiàn)的問(wèn)題,特別是當(dāng)項(xiàng)目引入多個(gè)第三方庫(kù)或框架時(shí),依賴沖突可能導(dǎo)致編譯錯(cuò)誤、運(yùn)行時(shí)異?;虿豢深A(yù)測(cè)的行為,本文給大家介紹了如何在SpringBoot項(xiàng)目中解決以來(lái)沖突問(wèn)題的方法,需要的朋友可以參考下
    2024-01-01
  • java并發(fā)編程synchronized底層實(shí)現(xiàn)原理

    java并發(fā)編程synchronized底層實(shí)現(xiàn)原理

    這篇文章主要介紹了java并發(fā)編程synchronized底層實(shí)現(xiàn)原理
    2022-02-02
  • Java并發(fā)編程之線程池實(shí)現(xiàn)原理詳解

    Java并發(fā)編程之線程池實(shí)現(xiàn)原理詳解

    池化思想是一種空間換時(shí)間的思想,期望使用預(yù)先創(chuàng)建好的對(duì)象來(lái)減少頻繁創(chuàng)建對(duì)象的性能開(kāi)銷(xiāo),java中有多種池化思想的應(yīng)用,例如:數(shù)據(jù)庫(kù)連接池、線程池等,下面就來(lái)具體講講
    2023-05-05
  • 解析Java中的默認(rèn)方法

    解析Java中的默認(rèn)方法

    這篇文章主要介紹了Java中的默認(rèn)方法,包括繼承和調(diào)用等Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-07-07
  • Spring使用redis遇到的問(wèn)題及解決方案

    Spring使用redis遇到的問(wèn)題及解決方案

    這篇文章主要介紹了Spring使用redis遇到的問(wèn)題及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring中BeanFactory?FactoryBean和ObjectFactory的三種的區(qū)別

    Spring中BeanFactory?FactoryBean和ObjectFactory的三種的區(qū)別

    關(guān)于FactoryBean?和?BeanFactory的對(duì)比文章比較多,但是對(duì)ObjectFactory的描述就比較少,今天我們對(duì)比下這三種的區(qū)別,感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • 基于Java Callable接口實(shí)現(xiàn)線程代碼實(shí)例

    基于Java Callable接口實(shí)現(xiàn)線程代碼實(shí)例

    這篇文章主要介紹了基于Java Callable接口實(shí)現(xiàn)線程代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Spring Cloud引入Eureka組件,完善服務(wù)治理

    Spring Cloud引入Eureka組件,完善服務(wù)治理

    這篇文章主要介紹了Spring Cloud引入Eureka組件,完善服務(wù)治理的過(guò)程詳解,幫助大家更好的理解和使用spring cloud,感興趣的朋友可以了解下
    2021-02-02

最新評(píng)論