前言:看了許多博客和書,都對自定異常一筆帶過,總讓人感覺莫名奇妙,一直在問自己一個問題,我們能很好的解決異常就很不錯了,爲什麼還要自己自定義異常,讓自己去自找麻煩呢?後來我才理解自定義異常有自己的妙用。
Java錯誤與異常的基本概念:
1.java中異常均繼承自Throwable,其有兩個重要的直接子類error與exception.
2.java錯誤error,大部分是由虛擬機爆出來的錯誤,是程序無法處理的錯誤,如OutOfMemoryError,當JVM需要更多內存空間而得不到滿足時,就會爆出OutOfMemoryError。
3.Exception,異常,其下分類很多,如可查異常與不可查異常,運行時異常與非運行時異常,基本概念一樣,只是說法不同罷了。其有個重要的子類即RuntimeException運行時異常,其它直接子類都歸爲非RuntimeException,如IOException,SQLException等。
a.非RuntimeException是在代碼書寫時,編譯器給你檢查提示你要進行try catch或throws處理。
b.RuntimeException,編譯器不會幫你自動檢查,當你運行程序時,虛擬機纔會給你爆出錯誤讓你去處理,這個往往是我們編碼邏輯或不規範導致的
下面我們來看看java異常類結構層次圖:
異常中的try,catch,throw,throws,finally,相信都能很好理解,下面我重點來說自定義異常了。
JAVA自定義異常:
自定義異常幾步驟:
1.自定義一個類,集成自Exception
2.重寫父類Exception所有的公共方法
3.重載構造函數
那爲什麼要自定義異常呢,這就涉及到項目結構中的分層思想了,根據MVC架構,一個項目可大體分爲3個層次,
1.是模型層model,這個往往與數據庫中的表結構相對應,今天內容不涉及該層可忽略。
2.是業務邏輯層Contorler,往往處理的是業務邏輯的,如對數據庫的增刪改查,業務邏輯的判斷等。
3.是界面層view,是與用戶交互的層次,往往只用於刷新顯示界面
這些層次都有自己的使命,view層不能又進行業務邏輯的處理又進行界面顯示刷新的操作,這樣管理維護代碼就清晰多了,那麼隨之問題就來了,但我業務邏輯層做了邏輯判斷之後想要view層根據不同的業務進行ui顯示時又該怎麼做呢?這個就需要我們自定義異常類登場了。我們以簡單密碼校驗爲例:
我們只對密碼進行校驗,當登錄時如果密碼爲123提示登錄成功,否則提示失敗
import java.util.Scanner;
public class Login {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String pw = scan.nextLine();
if ("123".equals(pw)) {
System.out.println("登錄成功");
}else{
System.out.println("登錄失敗");
}
}
}
這個是很直接的寫法,邏輯判斷與界面刷新顯示都在view層去處理了,這種寫法不是我們想要的,等到我們項目變大後你會發現view層做界面顯示又做邏輯處理是多麼的愚蠢。
下面我們用分層思想去實現該功能。
1.我們先自定義異常類 MyException
import java.io.PrintStream;
import java.io.PrintWriter;
@SuppressWarnings("serial")
public class MyException extends Exception{
/**
* 重載構造函數
*/
public MyException() {
super();
}
public MyException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(String message) {
super(message);
}
public MyException(Throwable cause) {
super(cause);
}
/**
* 重寫父類的方法
*/
@Override
public String getMessage() {
// TODO Auto-generated method stub
return super.getMessage();
}
@Override
public String getLocalizedMessage() {
// TODO Auto-generated method stub
return super.getLocalizedMessage();
}
@Override
public synchronized Throwable getCause() {
// TODO Auto-generated method stub
return super.getCause();
}
@Override
public synchronized Throwable initCause(Throwable cause) {
// TODO Auto-generated method stub
return super.initCause(cause);
}
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
@Override
public void printStackTrace() {
// TODO Auto-generated method stub
super.printStackTrace();
}
@Override
public void printStackTrace(PrintStream s) {
// TODO Auto-generated method stub
super.printStackTrace(s);
}
@Override
public void printStackTrace(PrintWriter s) {
// TODO Auto-generated method stub
super.printStackTrace(s);
}
@Override
public synchronized Throwable fillInStackTrace() {
// TODO Auto-generated method stub
return super.fillInStackTrace();
}
@Override
public StackTraceElement[] getStackTrace() {
// TODO Auto-generated method stub
return super.getStackTrace();
}
@Override
public void setStackTrace(StackTraceElement[] stackTrace) {
// TODO Auto-generated method stub
super.setStackTrace(stackTrace);
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
return super.equals(obj);
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
}
}
然後寫我的業務邏輯層LoginService
public class LoginService {
//這裏不能講exception try catch ,將它拋出去讓view層去捕獲,再進行處理
public void vertifyPw(String pw) throws MyException{
if ("123".equals(pw)) {
throw new MyException("登錄成功");
}else{
throw new MyException("登錄失敗");
}
}
}
最後刷新view
import java.util.Scanner;
public class Login {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String pw = scan.nextLine();
LoginService ls = new LoginService();
// 這裏調用vertifyPw(),方法進行校驗,根據不同的返回值做打印輸出e.getMessage();
try {
ls.vertifyPw(pw);
} catch (MyException e) {
System.out.println(e.getMessage());
}
}
}
我在註釋中已對關鍵地方做了註解,看代碼應該很容易能理解到自定義異常的好處了吧!
結語:不要嘆氣,你現在走的每一步都是爲你昨天的選擇買單,換句話說,這也叫擔當!