大話Java異常

異常

異常的概述


  • 異常就是不正常的意思,Java語言中主要是指程序在運行階段產生的錯誤
  • Throwable(可拋出的,可扔出的)
    • java.lang.Throwable 類是Java程序所有錯誤或異常的超類
    • 主要有兩個字類
      • Error
        • Error主要描述比較嚴重的錯誤
        • 無法通過編程來解決的重大的錯誤
      • Exception
        • Exception主要m描述比較輕量級的錯誤
        • 可以通過編程來解決

Exception類的主要分類

RuntimeException -> 運行時異常,也叫非檢測性異常類


  • 非檢測性異常類就是指b編譯階段無法被編譯器檢測出來的異常
  • 主要子類
    • ArithmeticException -> 算數異常類
    • ArrayIndexOutOfBoundsException(間接子類) -> 數組下標異常類
    • NullPointerException -> 空指針異常
    • ClassCastException -> 類型轉換異常
    • NumberFormatException(間接子類)-> 數字格式異常
  • 注意
    • 當程序的執行過程中產生異常,若沒有手動進行處理,則由Java虛擬機採用默認的方式進行處理,默認方式是打印異常名稱、異常原因以及異常發生的位置並終止程序,後序代碼無法被執行

IOException和其他異常類 -> 其他異常類,也叫做非檢測性異常

案例

TestRuntimeException.java

package demo1;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

/*
 * 		ArithmeticException -> 算數異常類
		ArrayIndexOutOfBoundsException(間接子類) -> 數組下標異常類
		NullPointerException -> 空指針異常
		ClassCastException -> 類型轉換異常
		NumberFormatException(間接子類)-> 數字格式異常
 */

public class TestRuntimeException {
	public static void main(String[] args) {
		
		
		// 觀察檢測性異常
		// FileInputStream fis = new FileInputStream("c:/a.txt");
	
		// java.lang.ArithmeticException 算數異常
		int a = 10; 
		int b = 0;
		if (b != 0) {
			System.out.println(a/b);
		}

		// java.lang.ArrayIndexOutOfBoundsException 數組下標越界異常

		int[] arr = new int[3];
		int num = 3;
		if (num >= 0 && num < arr.length) {
			System.out.println(arr[num]);
		}
 

		// java.lang.NullPointerException

		String str = null; 
		if (str != null) {
			System.out.println(str.length());
		}

		// java.lang.ClassCastException

		Exception ex = new Exception(); 
		if (ex instanceof IOException) {
			IOException ie = (IOException) ex;
		}

		// java.lang.NumberFormatException

		String s = "12be"; 
		if (s.matches("\\d+")) {
			System.out.println(Integer.parseInt(s));
		}
		System.out.println("運行程序結束");

	}
}

異常處理

運行時異常的處理方式


  • 對於絕大數運行時異常來說,都可以通過條件判斷避免異常的發生

異常的捕獲


  • 語法格式
    try{
    可能產生異常對象的語句塊
    }catch(異常類型 引用名){
    針對當前異常類型對象的處理語句塊
    }
    … (可以寫多個catch)
    finally{
    無論是否發生異常,都應該執行的語句塊
    }

  • 注意事項

    • 當捕獲的結構中有多個catch分支時,切記小範圍的異常類型放在大範圍的異常類型上面
    • 懶人寫法:
      catch(Exception e) {…}
  • 執行流程

      try {
      	a;
      	b;  // 可能產生異常的語句
      	c;
      } catch (Exception e) {
      	e;
      } finally {
      	f;
      }
    
    • 當沒有產生異常的時候,程序的執行流程是:a b c f
    • 當產生異常時,程序的執行流程是: a b e f
  • 案例

    • TestExceptionCatch.java
    package demo2;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class TestExceptionCatch {
    	public static void main(String[] args) {
    	
    		// 聲明引用指向本類的對象,用於讀取文件中的內容
    		FileInputStream fis = null;
    		try {
    			// 隨時可能產生文件找不到y異常對象, new FileNotFoundException()
    			fis = new FileInputStream("d:/a.txt");
    		} catch (FileNotFoundException e) {
    			// 打印異常的名稱、異常原因、異常的位置等信息
    			e.printStackTrace();
    		}
    		
    		try {
    			fis.close();
    		} catch (IOException e) {
    			
    			e.printStackTrace();
    		} catch (NullPointerException e) {
    			// System.out.println("輸出");
    			e.printStackTrace();
    		}
    	}
    }
    
    
    • TestFinally.java
    package demo3;
    
    public class TestFinally {
    	public static void main(String[] args) {
    		int a = 10;
    		int b = 0;
    		
    		try {
    			System.out.println(a/b);
    		} catch (Exception e) {
    			e.printStackTrace();
    			return ;
    		} finally {
    			System.out.println("無論是否發生異常都會執行");
    		}
    		System.out.println("程序結束");
    	}
    }
    
    
      java.lang.ArithmeticException: / by zero
      無論是否發生異常都會執行
      at demo3.TestFinally.main(TestFinally.java:9)
    

異常的拋出

  • 基本概念
    • 某些特殊的場合中,當產生異常後卻無法直接處理/不想處理時,此時就可以將異常轉移給當前方法的調用者,這就叫異常的拋出
  • 語法格式
    • 返回值類型 方法名稱(形參列表) throws 異常類型{…}
  • 方法重寫的原則
    • 要求方法名相同、參數列表相同、返回值類型也相同,從jdk1.5開始允許返回子類類型
    • 範圍權限不能變小,可以相同或者變大
    • 不能拋出更大的異常
    • 注意
      • 子類中重寫以後的方法可以選擇拋出與父類一樣的異常、更小的異常、不拋出異常,但是不能拋出更大的異常、不同的異常
      • 案例
        A.java
        package demo4;
        
        import java.io.IOException;
        
        public class A {
        	public void show() throws IOException{
        		System.out.println("A");
        	}
        }
        
        
        SubA.java
        package demo4;
        
        import java.io.IOException;
        import java.io.FileNotFoundException;
        import javax.print.PrintException;
        
        public class SubA extends A{
        
        	@Override
        	// public void show() throws IOException {
        	// public void show() throws FileNotFoundException {
        	// public void show() throws PrintException {
        	// public void show() throws Exception {
        	public void show() {
        	}
        }
        
        

      顯然不能拋出更大的異常

自定義異常

  • 自定義異常的由來

    • Java官方庫中雖然提供了大量的異常類,但不足以描述現實生活中所有的異常情況。當出現官方庫中沒有m描述的異常情況,這個時候就需要程序員自定義異常類加以描述,使得異常信息更加具備針對性和可讀性
  • 自定義異常的流程

    • 自定義類繼承自Exception類或者Exception類的子類
    • 提供兩個版本的構造方法,一個是無參構造方法,另一個是字符串做參數的構造方法
  • 自定義異常 – >案例1

    • Person.java
    package demo5;
    
    public class Person {
    	private String name;
    	private int age;
    	
    	
    	
    	public Person() {
    		super();
    	}
    	public Person(String name, int age) throws Exception {
    		super();
    		setName(name);
    		setAge(age);
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getAge() {
    		return age;
    	}
    	public void setAge(int age) throws Exception {
    		if(age > 0 && age < 150) {
    			this.age = age;
    		} else {
    			// System.out.println("年齡不合理");
    			// 手動產生一個異常對象並拋出
    			// throw new Exception();
    			throw new AgeException("年齡不合理!");
    		}
    		System.out.println("產生異常的效果");
    	}
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + "]";
    	}
    	
    	
    }
    
    
    • AgeException.java
    package demo5;
    
    public class AgeException extends Exception {
    	
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    
    	// 自定義無參的構造方法
    	public AgeException() {
    		
    	}
    	
    	// 自定義使用字符串作爲參數的構造方法
    	public AgeException(String msg) {
    		super(msg);
    	}
    }
    
    
    • TestPerson.java
    package demo5;
    
    public class TestPerson {
    	public static void main(String[] args) {
    	
    		Person p = null;
    		try {
    			p = new Person("張三", -12);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		System.out.println(p);
    	}
    }
    
    
      demo5.AgeException: 年齡不合理!
      null
      at demo5.Person.setAge(Person.java:33)
      at demo5.Person.<init>(Person.java:15)
      at demo5.TestPerson.main(TestPerson.java:8)
    
  • 自定義異常 – > 案例2

    • Student.java
    package demo6;
    
    public class Student {
    	private String name;
    	private int id;
    	
    	
    	public Student() {
    		super();
    	}
    	public Student(String name, int id) throws IDException {
    		super();
    		setName(name);
    		setId(id);
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) throws IDException {
    		if (id > 0) {
    			this.id = id;
    		} else {
    			// System.out.println("學號不合理");
    			throw new IDException("學號不合理");
    		}
    		System.out.println("結束");
    	}
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", id=" + id + "]";
    	}
    	
    	
    }
    
    
    • IDException.java
    package demo6;
    
    public class IDException extends Exception {
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    
    	public IDException() {
    		
    	}
    	
    	public IDException(String msg) {
    		super(msg);
    	}
    }
    
    
    • TestStudent.java
    package demo6;
    
    public class TestStudent {
    	public static void main(String[] args) throws IDException {
    		
    		/*Student stu = null;
    		try {
    			stu = new Student("小王", -5);
    		} catch (IDException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}*/ 
    		
    		Student stu = new Student("小王", -5);
    		System.out.println(stu);
    	}
    }
    
    
      Exception in thread "main" demo6.IDException: 學號不合理
      at demo6.Student.setId(Student.java:30)
      at demo6.Student.<init>(Student.java:14)
      at demo6.TestStudent.main(TestStudent.java:14)
    

此處有一點要注意,在案例一的TestPerson中,在main函數中,我們使用try…catch語句,異常由內部進行處理,會打印後面的語句
而在案例二的TestStudent中,我們將異常直接交給main函數處理,也就是交給虛擬機處理,所以並不會執行後面的語句

異常對象的拋出

  • throw new 異常類型()
  • 例如:
    • throw new Exception()

最後簡單介紹一下throws和throw的區別

throws和throw的區別

  • throws
    • 用在方法聲明後面,跟的是異常類名
    • 可以跟多個異常類名,用逗號隔開
    • 表示拋出異常,由該方法的調用者來處理
    • throws表示出現異常的一種可能性,並不一定會發生這些異常
  • throw
    • 用在方法體內,跟的異常對象名
    • 只能拋出一個異常對象名
    • 表示拋出異常,由方法體內的語句實現
    • throw則是拋出了異常,執行throw則一定拋出了某種異常
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章