主頁 > 後端開發 > 【Java】??認識例外、例外的基本使用、認識例外(例外詳解)??

【Java】??認識例外、例外的基本使用、認識例外(例外詳解)??

2021-09-26 13:03:09 後端開發

目錄

    • 前言
      • 一、 例外的背景
          • 例外體系:
          • 防御式編程:
          • 例外的好處
      • 二、例外的基本用法
            • 基本語法
            • 關于例外的處理方式
            • 拋出例外
      • 三、 自定義例外類

前言

本篇文章你會學習到什么是例外,例外的基本語法使用,和自定義例外,干貨多多!!!

在這里插入圖片描述


一、 例外的背景

初識例外

我們曾經的代碼中已經接觸了一些 “例外” 了. 例如

除以 0

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

算術例外:
在這里插入圖片描述
陣列下標越界

陣列越界

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

訪問 null 物件

空指標例外

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

例外分為2種:

  • 運行時例外(非受查例外)
    • 算數例外 陣列越界例外 空指標例外 都是程式運行的程序當中發生的例外
  • 編譯時例外(受查例外)
    • 比如使用clone方法 在編譯前就劃紅線了就是編譯時例外
      在這里插入圖片描述

例外體系:

在這里插入圖片描述

我們來看一下空指標例外(其實是一個類繼承了運行時例外)
在這里插入圖片描述
對應上面的圖,

在看一下運行時例外:繼承了Exception(也可以看上面的圖)
在這里插入圖片描述
看一下Exception 繼承了Throwable:
在這里插入圖片描述

通過這個圖我們得到一個結論:每一個例外都是一個類,例外之間的關系 參考圖上繼承

我們看看Error

在這里插入圖片描述

這個就叫做錯誤
在這里插入圖片描述

例外和錯誤的區別:

錯誤:必須由程式員處理邏輯錯誤
例外:處理例外就OK了接下來繼續看


防御式編程:

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

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

注意!!! 上面這兩個概念千萬不要背!
其實很好理解, 舉個栗子~~
比如老濕年輕的時候, 和你們師娘剛開始談物件. 我們都知道, 談物件需要有一些親密的動作, 比如 “拉小手” 這 種. emmmmm 問題來了, 老濕去拉師娘的小手有兩種方式:

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

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

例外的核心思想就是 EAFP.


例外的好處

例如, 我們用偽代碼演示一下開始一局王者榮耀的程序.
LBYL 風格的代碼(不使用例外)

boolean ret = false;
ret = 登陸游戲();
if (!ret) {
 處理登陸游戲錯誤;
    return; }
ret = 開始匹配();
if (!ret) {
 處理匹配錯誤;
    return; }
ret = 游戲確認();
if (!ret) {
 處理游戲確認錯誤;
    return; }
ret = 選擇英雄();
if (!ret) {
    處理選擇英雄錯誤;
    return; }
ret = 載入游戲畫面();
if (!ret) {
 處理載入游戲錯誤;
    return; }

EAFP 風格的代碼(使用例外)

try {
    登陸游戲();
    開始匹配();
    游戲確認();
    選擇英雄();
    載入游戲畫面();
   ...
} catch (登陸游戲例外) {
    處理登陸游戲例外;
} catch (開始匹配例外) {
 處理開始匹配例外;
} catch (游戲確認例外) {
 處理游戲確認例外;
} catch (選擇英雄例外) {
 處理選擇英雄例外;
} catch (載入游戲畫面例外) {
 處理載入游戲畫面例外; }

對比兩種不同風格的代碼, 我們可以發現, 使用第一種方式, 正常流程和錯誤處理流程代碼混在一起, 代碼整體顯的比較混亂. 而第二種方式正常流程和錯誤流程是分離開的, 更容易理解代碼


二、例外的基本用法

基本語法

在這里插入圖片描述

  • try 代碼塊中放的是可能出現例外的代碼.
  • catch 代碼塊中放的是出現例外后的處理行為.
  • finally 代碼塊中的代碼用于處理善后作業, 會在最后執行.
  • 其中 catch 和 finally 都可以根據情況選擇加或者不加.

代碼:

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

在這里插入圖片描述
解釋:

在這里插入圖片描述

我們發現一旦出現例外, 程式就終止了. after 沒有正確輸出

為什么?

當沒有處理例外的時候一旦程式發生了例外之后,這個例外會交給jvm,如果給jvm處理例外,那么程式一定會終止,


我們來自己處理例外:catch一定要捕獲相應的例外(沒有捕獲到就交給了JVM了)
在這里插入圖片描述
結果:
在這里插入圖片描述
但是下面的也不會執行了
在這里插入圖片描述
相比上面的我們處理了例外,讓程式可以繼續運行下去了


那上面是沒有例外訊息的提示了,我們還想要些提示怎么搞呢??

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

在這里插入圖片描述
這個紅字可以進行參考,


代碼示例 catch 可以有多個:

在這里插入圖片描述

一段代碼可能會拋出多種不同的例外, 不同的例外有不同的處理方式. 因此可以搭配多個 catch 代碼塊.
如果多個例外的處理方式是完全相同, 也可以寫成這樣


代碼示例 也可以用一個 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");

為什么不推薦了,因為exception 范圍太大了,不好排查


代碼示例 finally 的執行不需要條件

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 無論有沒有例外都會最后執行


代碼示例 使用 try 負責回收資源

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

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

代碼示例 如果向上一直傳遞都沒有合適的方法處理例外, 最終就會交給 JVM 處理, 程式就會例外終止(和我們最開始未使用 try catch 時是一樣的).

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]);
}
// 直接結果
java.lang.ArrayIndexOutOfBoundsException: 100
 at demo02.Test.func(Test.java:18)
 at demo02.Test.main(Test.java:9)
after try catch

可以看見上面代碼是func可以有例外,但是在main方法里面處理了的


例外處理流程

  • 程式先執行 try 中的代碼

  • 如果 try 中的代碼出現例外, 就會結束 try 中的代碼, 看和 catch 中的例外型別是否匹配.

  • 如果找到匹配的例外型別, 就會執行 catch 中的代碼

  • 如果沒有找到匹配的例外型別, 就會將例外向上傳遞到上層呼叫者.

  • 無論是否找到匹配的例外型別, finally 中的代碼都會被執行到(在該方法結束之前執行).

  • 如果上層呼叫者也沒有處理的了例外, 就繼續向上傳遞.

  • 一直到 main 方法也沒有合適的代碼處理例外, 就會交給 JVM 來進行處理, 此時程式就會例外終止.

關于例外的處理方式

例外的種類有很多, 我們要根據不同的業務場景來決定.

對于比較嚴重的問題(例如和算錢相關的場景), 應該讓程式直接崩潰, 防止造成更嚴重的后果

對于不太嚴重的問題(大多數場景), 可以記錄錯誤日志, 并通過監控報警程式及時通知程式猿

對于可能會恢復的問題(和網路相關的場景), 可以嘗試進行重試.

在我們當前的代碼中采取的是經過簡化的第二種方式. 我們記錄的錯誤日志是出現例外的方法呼叫資訊, 能很快

速的讓我們找到出現例外的位置. 以后在實際作業中我們會采取更完備的方式來記錄例外資訊


拋出例外

除了 Java 內置的類會拋出一些例外之外, 程式猿也可以手動拋出某個例外. 使用 throw 關鍵字完成這個操作

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; 
} 
// 執行結果
Exception in thread "main" java.lang.ArithmeticException: 拋出除 0 例外
 at demo02.Test.divide(Test.java:14) 
 at demo02.Test.main(Test.java:9)

在這個代碼中, 我們可以根據實際情況來拋出需要的例外. 在構造例外物件同時可以指定一些描述性資訊.

例外說明
我們在處理例外的時候, 通常希望知道這段代碼中究竟會出現哪些可能的例外.

我們可以使用 throws 關鍵字, 把可能拋出的例外顯式的標注在方法定義的位置. 從而提醒呼叫者要注意捕獲這些例外.

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

三、 自定義例外類

Java 中雖然已經內置了豐富的例外類, 但是我們實際場景中可能還有一些情況需要我們對例外類進行擴展, 創建符合我們實際情況的例外.

我們先看一下其他的例外大概是個怎么樣的一個體系:
在這里插入圖片描述
空指標例外是繼承了個運行時例外,不過他里面的方法寫的不是很多,也就是兩個幫父類的構造方法,所以按照它這樣的我們也可以寫一個自己的例外,


創建一個例外類:
在這里插入圖片描述
使用:
在這里插入圖片描述
結果:
在這里插入圖片描述
以上就是我們的一個自定義例外


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

在這里插入圖片描述
這里發現報錯了,為什么?我們在來看一下例外體系結構

在這里插入圖片描述
這個時候編譯器不知道是編譯時例外還是運行時例外,所以默認選擇權限小的編譯時例外,這個時候我們要拋出例外
在這里插入圖片描述
上面的沒有報錯了下面的開始了?為什么?因為我們拋出編譯時例外,我們要try catch一下:
在這里插入圖片描述
所以這個就是一個自定義例外,

在舉一個例子:

例如, 我們實作一個用戶登陸功能:(如果用戶名錯誤處理用戶名的錯誤,密碼錯誤處理密碼錯誤)

在這里插入圖片描述

此時我們在處理用戶名密碼錯誤的時候可能就需要拋出兩種例外. 我們可以基于已有的例外類進行擴展(繼承), 創建和我們業務相關的例外類

在這里插入圖片描述
自己寫的類

我們可以在login里面這樣寫:
在這里插入圖片描述
主方法:
在這里插入圖片描述
這樣就是使用我們自己的例外,

注意事項

  • 自定義例外通常會繼承自 Exception 或者 RuntimeException
  • 繼承自 Exception 的例外默認是受查例外
  • 繼承自 RuntimeException 的例外默認是非受查例外.

以上就是例外的全部內容了,如果有什么不對的地方歡迎評論指正謝謝!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/303033.html

標籤:java

上一篇:人的一生會遇到三種人,一個驚艷了時光,一個溫柔了歲月,一個講懂了“堆”

下一篇:javaSE初階 String

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more