C# 建立音訊WAVE檔案頭資訊(*.wav)
0x01.異常
異常概念,體系,分類,異常產生過程解析
1、異常概念
異常,就是不正常的意思。在生活中:醫生說,你的身體某個部位有異常,該部位和正常相比有點不同,該部位的功能將受影響.在程式中的意思就是:
- 異常 :指的是程式在執行過程中,出現的非正常的情況,最終會導致JVM的非正常停止。
注意: 在Java等面向物件的程式語言中,異常本身是一個類,產生異常就是建立異常物件並丟擲了一個異常物件。Java處理異常的方式是中斷處理。
異常指的並不是語法錯誤,語法錯了,編譯不通過,不會產生位元組碼檔案,根本不能執行.
2、 異常體系
異常機制其實是幫助我們找到程式中的問題,異常的根類是java.lang.Throwable
java.lang.Error
與java.lang.Exception
,平常所說的異常指java.lang.Exception
。
Throwable體系:
- Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免,好比絕症。
- Exception:表示異常,異常產生後程序員可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的。好比感冒、闌尾炎。
3、異常分類
我們平常說的異常就是指Exception,因為這類異常一旦出現,我們就要對程式碼進行更正,修復程式。
異常(Exception)的分類:根據在編譯時期還是執行時期去檢查異常?
- 編譯時期異常:checked異常。在編譯時期,就會檢查,如果沒有處理異常,則編譯失敗。(如日期格式化異常)
- 執行時期異常:runtime異常。在執行時期,檢查異常.在編譯時期,執行異常不會編譯器檢測(不報錯)。(如數學異常)
public class Test { public static void main(String[] args) { /* 異常的概述: - 異常概念: 程式執行期間,出現的不正常情況,導致jvm終止程式執行 注意: java是面嚮物件語言,異常本身也是一個類,當出現異常的時候,就會建立該異常類的物件並丟擲該異常物件 建立異常物件,該物件就會包裝異常的型別,異常的資訊,異常的位置等資訊 - 異常體系 Throwable類:是 Java 語言中所有錯誤或異常的超類\父類 Error類: 表示錯誤,無法通過程式碼進行糾正,只能事先避免,相當於:絕症 例如: 棧記憶體溢位錯誤,伺服器宕機,資料庫奔潰... Exception類:表示異常,可以通過程式碼進行糾正,相當於: 感冒... - 異常分類 編譯異常:在編譯期間,出現的異常,導致程式無法通過編譯,這就是編譯異常 除了RuntimeException及其子類都是編譯異常 執行異常:在執行期間,才出現的異常,編譯期間不處理,編譯可以通過,這就是執行異常 RuntimeException及其子類都是執行異常 */ // 異常和錯誤 System.out.println("開始"); //System.out.println(1/0);// 異常 //method();// StackOverflowError 錯誤 System.out.println("結束"); // 例如: 編譯異常 //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //Date date = sdf.parse("1999-10-10"); // 例如: 執行異常 //System.out.println(1/0);// 異常 } public static void method(){ System.out.println("1"); method(); } }
4、異常的產生過程解析
先執行下面的程式,程式會產生一個數組索引越界異常ArrayIndexOfBoundsException。我們通過圖解來解析下異常產生的過程。
測試類
public class Test {
public static void main(String[] args) {
int[] arr = { 34, 12, 67 };
int num = getElement(arr, 4);
System.out.println("num=" + num);
System.out.println("over");
}
// 對給定的陣列通過給定的角標獲取元素。
public static int getElement(int[] arr, int index) {
int element = arr[index];
return element;
}
}
上述程式執行過程圖解:
0x02.異常的產生和處理
1、異常的產生
** 目標**
- 能夠理解使用throw關鍵字產生異常
** 路徑**
- throw關鍵字的作用
- throw關鍵字的使用格式
- 案例演示
講解:
throw關鍵字的作用
在java中,提供了一個throw關鍵字,它用來丟擲一個指定的異常物件。throw用在方法內,用來丟擲一個異常物件,將這個異常物件傳遞到呼叫者處,並結束當前方法的執行。
throw關鍵字的使用格式
throw new 異常類名(引數);
例如:
throw new NullPointerException("要訪問的arr陣列不存在");
throw new ArrayIndexOutOfBoundsException("該索引在陣列中不存在,已超出範圍");
案例演示
public class Student {
//姓名
private String name;
//年齡
private int age;
//構造方法
public Student() {
}
public Student(String name, int age) {
this.name = name;
//對年齡的判斷
if(age >= 0) {
this.age = age;
}else{
//如果年齡是負數,就讓他報錯
throw new RuntimeException("年齡不能是" + age);
}
}
//set get
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
//對年齡的判斷
if(age >= 0) {
this.age = age;
}else{
//如果年齡是負數,就讓他報錯
throw new RuntimeException("年齡不能是" + age);
}
}
//toString
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Demo02_異常的產生 {
public static void main(String[] args) {
//正常情況下,年齡不可能是一個負數
//要求:賦值正數正常賦值,賦值負數就讓程式碼報錯!
//建立物件
Student s = new Student("柳巖",36);
System.out.println(s);
//建立物件
Student s2 = new Student();
s2.setName("美美");
s2.setAge(-20);
System.out.println(s2);
}
}
2、宣告處理異常
目標
- 掌握宣告處理異常
路徑
- 宣告處理異常的概述
- 宣告處理異常格式
講解
宣告處理異常的概述
宣告處理異常:使用throws關鍵字將異常標識出來, 表示當前方法不處理異常,而是提醒給呼叫者, 讓呼叫者來處理....最終會到虛擬機器,虛擬機器直接結束程式,列印異常資訊。
宣告處理異常格式
修飾符 返回值型別 方法名(引數) throws 異常類名1,異常類名2…{ // 可以丟擲一個,也可以多個
}
案例演示
public class Demo {
public static void main(String[] args) throws IOException{
method1();
}
public static void method3(int num) throws Exception {
if(num == 1) {
throw new IOException("IO異常");// 建立了一個編譯異常,並通過throw丟擲這個編譯異常
}else{
throw new ParseException("解析異常",1);
}
}
public static void method2(int num) throws IOException,ParseException{
if(num == 1) {
throw new IOException("IO異常");// 建立了一個編譯異常,並通過throw丟擲這個編譯異常
}else{
throw new ParseException("解析異常",1);
}
}
public static void method1() throws IOException{
throw new IOException("IO異常");// 建立了一個編譯異常,並通過throw丟擲這個編譯異常
}
}
0x03.捕獲處理異常try…catch
目標
- 掌握捕獲處理異常
路徑
- 捕獲處理異常的概述
- 捕獲處理異常格式
- 獲取異常資訊
講解
捕獲處理異常的概述
- 捕獲處理異常:對異常進行捕獲處理 , 處理完後程序可以正常向下執行。
捕獲處理異常格式
try{
編寫可能會出現異常的程式碼
}catch(異常型別 e){
處理異常的程式碼
//記錄日誌/列印異常資訊/繼續丟擲異常
}
執行步驟:
1.首先執行try中的程式碼,如果try中的程式碼出現了異常,那麼就直接執行catch()裡面的程式碼,執行完後,程式繼續往下執行
2.如果try中的程式碼沒有出現異常,那麼就不會執行catch()裡面的程式碼,而是繼續往下執行
注意:
- try和catch都不能單獨使用,必須連用。
- try中的程式碼出現了異常,那麼出現異常位置後面的程式碼就不會再執行了
- 捕獲處理異常,如果程式出現了異常,程式會繼續往下執行
宣告處理異常,如果程式出現了異常,程式就不會繼續往下執行
演示如下:
public class Demo {
public static void main(String[] args) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("1999年10月12日");
System.out.println(date);
}catch (Exception e){
System.out.println("出現了異常....");
}
System.out.println("結束");
}
}
獲取異常資訊
Throwable類中定義了一些檢視方法:
public String getMessage()
:獲取異常的描述資訊,原因(提示給使用者的時候,就提示錯誤原因。public String toString()
:獲取異常的型別和異常描述資訊(不用)。public void printStackTrace()
:列印異常的跟蹤棧資訊並輸出到控制檯。
** 包含了異常的型別,異常的原因,還包括異常出現的位置,在開發和除錯階段,都得使用printStackTrace。**
在開發中呢也可以在catch將編譯期異常轉換成執行期異常處理。
0x04.finally 程式碼塊
finally程式碼塊的概述
finally:有一些特定的程式碼無論異常是否發生,都需要執行。另外,因為異常會引發程式跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally程式碼塊中存放的程式碼都是一定會被執行的。
** finally程式碼塊的語法格式**
try{
可能會出現異常的程式碼
}catch(異常的型別 變數名){
處理異常的程式碼或者列印異常的資訊
}finally{
無論異常是否發生,都會執行這裡的程式碼(正常情況,都會執行finally中的程式碼,一般用來釋放資源)
}
執行步驟:
1.首先執行try中的程式碼,如果try中的程式碼出現了異常,那麼就直接執行catch()裡面的程式碼,執行完後會執行finally中的程式碼,然後程式繼續往下執行
2.如果try中的程式碼沒有出現異常,那麼就不會執行catch()裡面的程式碼,但是還是會執行finally中的程式碼,然後程式繼續往下執行
注意:finally不能單獨使用。
案例演示
public class Test {
public static void main(String[] args) {
/*
注意:
即使catch中有return,finally中的程式碼還是會執行
*/
Scanner sc = null;
try{
sc = new Scanner(System.in);
String s = sc.next();
System.out.println(1/0);// 出現異常,throw new ArithmeticException("");
}catch (Exception e){
System.out.println("出現了異常");
//return;// 結束方法 finally會執行
// System.exit(0);// 系統退出 finally不會執行
}finally{
sc.close();// 不會執行
System.out.println("關閉...");
}
System.out.println("======================");
/* Scanner sc2 = null;
try{
sc2 = new Scanner(System.in);
String s = sc2.next();
System.out.println(1/1);// 1 沒有異常
}catch (Exception e){
System.out.println("出現了異常");
}finally{
sc2.close();// 不會執行
System.out.println("關閉...");
}*/
System.out.println("結束");
}
}
當只有在try或者catch中呼叫退出JVM的相關方法,此時finally才不會執行,否則finally永遠會執行。
0x05.異常處理事項
-
執行時異常被丟擲可以不處理。即不捕獲也不宣告丟擲。
-
如果父類的方法丟擲了多個異常,子類覆蓋(重寫)父類方法時,只能丟擲相同的異常或者是他的子集。
-
父類方法沒有丟擲異常,子類覆蓋父類該方法時也不可丟擲異常。此時子類產生該異常,只能捕獲處理,不能宣告丟擲
-
當多異常分別處理時,捕獲處理,前邊的類不能是後邊類的父類
-
在try/catch後可以追加finally程式碼塊,其中的程式碼一定會被執行,通常用於資源回收。
-
多個異常使用捕獲又該如何處理呢?
- 多個異常分別處理。
- 多個異常一次捕獲,多次處理。
- 多個異常一次捕獲一次處理。
一般我們是使用一次捕獲多次處理方式,格式如下:
try{ 編寫可能會出現異常的程式碼 }catch(異常型別A e){ 當try中出現A型別異常,就用該catch來捕獲. 處理異常的程式碼 //記錄日誌/列印異常資訊/繼續丟擲異常 }catch(異常型別B e){ 當try中出現B型別異常,就用該catch來捕獲. 處理異常的程式碼 //記錄日誌/列印異常資訊/繼續丟擲異常 }
注意:這種異常處理方式,要求多個catch中的異常不能相同,並且若catch中的多個異常之間有子父類異常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。
程式碼如下:
public class Demo {
public static void main(String[] args) {
System.out.println(1/0);
}
/**
* 多個異常一次捕獲一次處理
* @param num
*/
public static void method3(int num) {
try {
if(num == 1) {
throw new IOException("IO異常");
}else{
throw new ParseException("解析異常",1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 多個異常一次捕獲,多次處理。
* @param num
*/
public static void method2(int num) {
try {
if(num == 1) {
throw new IOException("IO異常");
}else{
throw new ParseException("解析異常",1);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
/**
* 多個異常分別處理。
* @param num
*/
public static void method1(int num) {
if(num == 1) {
try {
throw new IOException("IO異常");
} catch (IOException e) {
e.printStackTrace();
}
}else{
try {
throw new ParseException("解析異常",1);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
0x06.自定義異常
自定義異常概述
為什麼需要自定義異常類:
我們說了Java中不同的異常類,分別表示著某一種具體的異常情況,那麼在開發中總是有些異常情況是SUN沒有定義好的,例如年齡負數問題,考試成績負數問題.這些異常在JDK中沒有定義過,此時我們根據自己業務的異常情況來定義異常類。
什麼是自定義異常類:
在開發中根據自己業務的異常情況來定義異常類.
自定義一個業務邏輯異常: RegisterException。一個註冊異常類。
異常類如何定義:
- 自定義一個編譯期異常: 自定義類 並繼承於
java.lang.Exception
。 - 自定義一個執行時期的異常類:自定義類 並繼承於
java.lang.RuntimeException
。
自定義異常的練習
要求:我們模擬註冊操作,如果使用者名稱已存在,則丟擲異常並提示:親,該使用者名稱已經被註冊。
首先定義一個註冊異常類RegisterException:
// 業務邏輯異常
public class RegisterException extends Exception {
/**
* 空參構造
*/
public RegisterException() {
}
/**
*
* @param message 表示異常提示
*/
public RegisterException(String message) {
super(message);
}
}
模擬登陸操作,使用陣列模擬資料庫中儲存的資料,並提供當前註冊賬號是否存在方法用於判斷。
public class Demo {
// 模擬資料庫中已存在賬號
private static String[] names = {"bill","hill","jill"};
public static void main(String[] args) {
//呼叫方法
try{
// 可能出現異常的程式碼
checkUsername("nill");
System.out.println("註冊成功");//如果沒有異常就是註冊成功
}catch(LoginException e){
//處理異常
e.printStackTrace();
}
}
//判斷當前註冊賬號是否存在
//因為是編譯期異常,又想呼叫者去處理 所以宣告該異常
public static boolean checkUsername(String uname) throws LoginException{
for (String name : names) {
if(name.equals(uname)){//如果名字在這裡面 就丟擲登陸異常
throw new LoginException("親"+name+"已經被註冊了!");
}
}
return true;
}
}