# 異常處理
轉:<http://www.importnew.com/26613.html>
- [1.簡介](#1_4)
- [2.Java異常的分類和類結構圖](#2Java_15)
- [2.1 錯誤](#21__21)
- [2.2 異常](#22__24)
- [2.2.1 異常分類](#221__27)
- [3.初識異常](#3_46)
- [4.異常處理的基本語法](#4_124)
- [4.1 try…catch…finally語句塊](#41_trycatchfinally_128)
## 1.簡介
程序運行時,發生的不被期望的事件,它阻止了程序按照程序員的預期正常執行,這就是異常。異常發生時,是任程序自生自滅,立刻退出終止,還是輸出錯誤給用戶?或者用C語言風格:用函數返回值作為執行狀態?。
**Java提供了更加優秀的解決辦法:異常處理機制。**
異常處理機制能讓程序在異常發生時,按照代碼的預先設定的異常處理邏輯,針對性地處理異常,讓程序盡最大可能恢復正常并繼續執行,且保持代碼的清晰。
Java中的異常可以是函數中的語句執行時引發的,也可以是程序員通過throw 語句手動拋出的,只要在Java程序中產生了異常,就會用一個對應類型的異常對象來封裝異常,JRE就會試圖尋找異常處理程序來處理異常。
**Throwable類是Java異常類型的頂層父類**,一個對象只有是 Throwable 類的(直接或者間接)實例,他才是一個異常對象,才能被異常處理機制識別。JDK中內建了一些常用的異常類,我們也可以自定義異常。
## 2.Java異常的分類和類結構圖
> Java標準庫內建了一些通用的異常,這些類以Throwable為頂層父類。**Throwable又派生出Error類和Exception類**。

### 2.1 錯誤
Error類以及他的子類的實例,代表了JVM本身的錯誤。錯誤不能被程序員通過代碼處理,Error很少出現。因此,程序員應該關注Exception為父類的分支下的各種異常類。
### 2.2 異常
Exception以及他的子類,代表程序運行時發送的各種不期望發生的事件。可以被Java異常處理機制使用,是異常處理的核心。
### **2.2.1 異常分類**
> 總體上我們根據Javac對異常的處理要求,將異常類分為2類
#### **1. 非檢查異常(unckecked exception):**
- **Error 和 RuntimeException 以及他們的子類。**
- javac在編譯時,不會提示和發現這樣的異常,不要求在程序處理這些異常。所以如果愿意,我們可以編寫代碼處理(使用try…catch…finally)這樣的異常,也可以不處理。
- **對于這些異常,我們應該修正代碼,而不是去通過異常處理器處理 。**
- 這樣的異常發生的原因多半是代碼寫的有問題。如除0錯誤ArithmeticException,錯誤的強制類型轉換錯誤ClassCastException,數組索引越界ArrayIndexOutOfBoundsException,使用了空對象NullPointerException等等。
#### **2. 檢查異常(checked exception):**
- 除了Error 和 RuntimeException的其它異常,javac強制要求程序員為這樣的異常做預備處理工作(使用try…catch…finally或者throws,IDE編寫代碼時,報出的異常都是檢查異常)。
- 在方法中要么用try-catch語句捕獲它并處理,要么用throws子句聲明拋出它,否則編譯不會通過。這樣的異常一般是由程序的運行環境導致的。因為程序可能被運行在各種未知的環境下,而程序員無法干預用戶如何使用他編寫的程序,于是程序員就應該為這樣的異常時刻準備著。如SQLException , IOException,ClassNotFoundException 等。
- 需要明確的是:檢查和非檢查是對于javac來說的,這樣就很好理解和區分了
## 3.初識異常
下面的代碼會演示2個異常類型:ArithmeticException 和 InputMismatchException。前者由于整數除0引發,后者是輸入的數據不能被轉換為int類型引發。
```
package com.example;
import java. util .Scanner ;
public class AllDemo
{
public static void main (String [] args )
{
System . out. println( "----歡迎使用命令行除法計算器----" ) ;
CMDCalculate ();
}
public static void CMDCalculate ()
{
Scanner scan = new Scanner ( System. in );
int num1 = scan .nextInt () ;
int num2 = scan .nextInt () ;
int result = devide (num1 , num2 ) ;
System . out. println( "result:" + result) ;
scan .close () ;
}
public static int devide (int num1, int num2 ){
return num1 / num2 ;
}
}
```
```
/*****************************************
----歡迎使用命令行除法計算器----
0
Exception in thread "main" java.lang.ArithmeticException : / by zero
at com.example.AllDemo.devide( AllDemo.java:30 )
at com.example.AllDemo.CMDCalculate( AllDemo.java:22 )
at com.example.AllDemo.main( AllDemo.java:12 )
----歡迎使用命令行除法計算器----
r
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor( Scanner.java:864 )
at java.util.Scanner.next( Scanner.java:1485 )
at java.util.Scanner.nextInt( Scanner.java:2117 )
at java.util.Scanner.nextInt( Scanner.java:2076 )
at com.example.AllDemo.CMDCalculate( AllDemo.java:20 )
at com.example.AllDemo.main( AllDemo.java:12 )
*****************************************/
```
**異常是在執行某個函數時引發的,而函數又是層級調用,形成調用棧的,因為,只要一個函數發生了異常,那么他的所有的caller都會被異常影響。當這些被影響的函數以異常信息輸出時,就形成的了異常追蹤棧。**
**異常最先發生的地方,叫做異常拋出點。**
**最上邊的異常就是異常拋出點(棧:先進后出)**

從上面的例子可以看出,當devide函數發生除0異常時,devide函數將拋出ArithmeticException異常,因此調用他的CMDCalculate函數也無法正常完成,因此也發送異常,而CMDCalculate的caller——main 因為CMDCalculate拋出異常,也發生了異常,這樣一直向調用棧的棧底回溯。\*\*這種行為叫做異常的冒泡,異常的冒泡是為了在當前發生異常的函數或者這個函數的caller中找到最近的異常處理程序。\*\*由于這個例子中沒有使用任何異常處理機制,因此異常最終由main函數拋給JRE,導致程序終止。
代碼中我選擇使用throws聲明異常,讓函數的調用者去處理可能發生的異常。但是為什么只throws了IOException呢?因為FileNotFoundException是IOException的子類,在處理范圍內。
```
@Test
public void testException() throws IOException
{
//FileInputStream的構造函數會拋出FileNotFoundException
FileInputStream fileIn = new FileInputStream("E:\\a.txt");
int word;
//read方法會拋出IOException
while((word = fileIn.read())!=-1)
{
System.out.print((char)word);
}
//close方法會拋出IOException
fileIn.clos
}
```
## 4.異常處理的基本語法
> 在編寫代碼處理異常時,對于檢查異常,有2種不同的處理方式:使用try…catch…finally語句塊處理它。或者,在函數簽名中使用throws 聲明交給函數調用者caller去解決。
### 4.1 try…catch…finally語句塊
```
try{
//try塊中放可能發生異常的代碼。
//如果執行完try且不發生異常,則接著去執行finally塊和finally后面的代碼(如果有的話)。
//如果發生異常,則嘗試去匹配catch塊。
}catch(SQLException SQLexception){
//每一個catch塊用于捕獲并處理一個特定的異常,或者這異常類型的子類。Java7中可以將多個異常聲明在一個catch中。
//catch后面的括號定義了異常類型和異常參數。如果異常與之匹配且是最先匹配到的,則虛擬機將使用這個catch塊來處理異常。
//在catch塊中可以使用這個塊的異常參數來獲取異常的相關信息。異常參數是這個catch塊中的局部變量,其它塊不能訪問。
//如果當前try塊中發生的異常在后續的所有catch中都沒捕獲到,則先去執行finally,然后到這個函數的外部caller中去匹配異常處理器。
//如果try中沒有發生異常,則所有的catch塊將被忽略。
}catch(Exception exception){
//...
}finally{
//finally塊通常是可選的。
//無論異常是否發生,異常是否匹配被處理,finally都會執行。
//一個try至少要有一個catch塊,否則, 至少要有1個finally塊。但是finally不是用來處理異常的,finally不會捕獲異常。
** //finally主要做一些清理工作,如流的關閉,數據庫連接的關閉等。 **
}
```
1\.try塊中的局部變量和catch塊中的局部變量(包括異常變量),以及finally中的局部變量,他們之間不可共享使用。
2\.每一個catch塊用于處理一個異常。異常匹配是按照catch塊的順序從上往下尋找的,只有第一個匹配的catch會得到執行。 **匹配時,不僅運行精確匹配,也支持父類匹配,** 因此,如果同一個try塊下的多個catch異常類型有父子關系,應該將子類異常放在前面,父類異常放在后面,這樣保證每個catch塊都有存在的意義。
3\.java中,異常處理的任務就是將**執行控制流***從異常發生的地方轉移到能夠處理這種異常的地方去*。也就是說:當一個函數的某條語句發生異常時,這條語句的后面的語句不會再執行,它失去了焦點。**執行流跳轉到最近的匹配的異常處理catch代碼塊去執行,異常被處理完后,執行流會接著在“處理了這個異常的catch代碼塊”后面接著執行。**
> 1\.有的編程語言當異常被處理后,控制流會恢復到異常拋出點接著執行,這種策略叫做:resumption model of exception handling(恢復式異常處理模式 )
> 2\.而Java則是讓執行流恢復到處理了異常的catch塊后接著執行,這種策略叫做:termination model of exception handling(終結式異常處理模式)
```
public static void main(String[] args){
try {
foo();
}catch(ArithmeticException ae) {
System.out.println("處理異常");
}
}
public static void foo(){
int a = 5/0; //異常拋出點
System.out.println("為什么還不給我漲工資!!!"); //////////////////////不會執行
}
```
- 計算機網絡
- 基礎_01
- tcp/ip
- http轉https
- Let's Encrypt免費ssl證書(基于haproxy負載)
- what's the http?
- 網關
- 網絡IO
- http
- 工具
- Git
- 初始本地倉庫并上傳
- git保存密碼
- Gitflow
- maven
- 1.生命周期命令
- 聚合與繼承
- 插件管理
- assembly
- 資源管理插件
- 依賴范圍
- 分環境打包
- dependencyManagement
- 版本分類
- 找不到主類
- 無法加載主類
- 私服
- svn
- gradle
- 手動引入第三方jar包
- 打包exe文件
- Windows
- java
- 設計模式
- 七大原則
- 1.開閉原則
- 2. 里式替換原則
- 3. 依賴倒置原則
- 4. 單一職責原則
- 單例模式
- 工廠模式
- 簡單工廠
- 工廠方法模式
- 抽象工廠模式
- 觀察者模式
- 適配器模式
- 建造者模式
- 代理模式
- 適配器模式
- 命令模式
- json
- jackson
- poi
- excel
- easy-poi
- 規則
- 模板
- 合并單元格
- word
- 讀取
- java基礎
- 類路徑與jar
- 訪問控制權限
- 類加載
- 注解
- 異常處理
- String不可變
- 跨域
- transient關鍵字
- 二進制編碼
- 泛型1
- 與或非
- final詳解
- Java -jar
- 正則
- 讀取jar
- map
- map計算
- hashcode計算原理
- 枚舉
- 序列化
- URLClassLoader
- 環境變量和系統變量
- java高級
- java8
- 1.Lambda表達式和函數式接口
- 2.接口的默認方法和靜態方法
- 3.方法引用
- 4.重復注解
- 5.類型推斷
- 6.拓寬注解的應用場景
- java7-自動關閉資源機制
- 泛型
- stream
- 時區的正確理解
- StringJoiner字符串拼接
- 注解
- @RequestParam和@RequestBody的區別
- 多線程
- 概念
- 線程實現方法
- 守護線程
- 線程阻塞
- 筆試題
- 類加載
- FutureTask和Future
- 線程池
- 同步與異步
- 高效簡潔的代碼
- IO
- ThreadLocal
- IO
- NIO
- 圖片操作
- KeyTool生成證書
- 壓縮圖片
- restful
- 分布式session
- app保持session
- ClassLoader.getResources 能搜索到的資源路徑
- java開發規范
- jvm
- 高并發
- netty
- 多線程與多路復用
- 異步與事件驅動
- 五種IO模型
- copy on write
- code style
- 布隆過濾器
- 筆試
- 數據庫
- mybatis
- mybatis與springboot整合配置
- pagehelper
- 分頁數據重復問題
- Java與數據庫之間映射
- 攔截器
- 攔截器應用
- jvm
- 堆內存測試
- 線程棧
- 直接內存
- 內存結構
- 內存模型
- 垃圾回收
- 調優
- 符號引用
- 運行參數
- 方法區
- 分帶回收理論
- 快捷開發
- idea插件
- 注釋模板
- git
- pull沖突
- push沖突
- Excel處理
- 圖片處理
- 合并單元格
- easypoi
- 模板處理
- 響應式編程
- reactor
- reactor基礎
- jingyan
- 規范
- 數據庫