首頁  >  問答  >  主體

java - 為什麼在程式碼中不建議直接拋RuntimeException呢?

使用 Error、RuntimeException、Throwable 和 Exception 等通用異常可防止呼叫方法以不同於應用程式產生的錯誤的方式處理真正的、系統產生的例外。

不合規程式碼範例

雷雷

合規解決方案

雷雷
曾经蜡笔没有小新曾经蜡笔没有小新2667 天前1446

全部回覆(5)我來回復

  • 滿天的星座

    滿天的星座2017-06-30 09:58:07

    這個很容易理解啊.
    打個簡單的比方. 現在做一個登錄有用戶不存在/密碼錯誤... 這些錯誤類型, 如果你直接使用RuntimeException 代碼要寫成這樣.

    throw new RuntimeException("user not found"); // 用户不存在
    throw new RuntimeException("password not match"); // 密码错误

    捕捉異常

    try {
        // ...逻辑
    } catch(RuntimeException e) {
        if("user not found".equals(e.getMessage())) {
            // ...逻辑
        } else if("password not match".equals(e.getMessage())) {
            // ...逻辑
        }
    }

    反之自訂異常實作如下:

    throw new UserNotFoundException("user not found"); // 用户不存在
    throw new PasswordNotMatchException("password not match"); // 密码错误

    捕捉異常

    try {
        // ...逻辑
    } catch(UserNotFoundException e) {
        // ...逻辑
    } catch(PasswordNotMatchException e) {
        // ...逻辑
    }

    透過message判斷處理異常邏輯有很多弊端, 例如message是動態的, 那將無法準確的處理.
    當然我們也可以定義一個通用的異常類型, 通過業務碼去判斷會更加準確, 同時也會減少異常類型的定義, 減少程式碼的冗餘. 下面有一段kotlin程式碼, 目前我是使用的這種處理方式.

    interface BizCode {
    
        val code: Int
        val msg: String
    }
    
    enum class BizCodes(override val code: Int, override val msg: String): BizCode {
    
        // ====================================================== //
        // 公共错误码 0 - 999                                      //
        // ====================================================== //
        /**
         * 未知错误.
         */
        C_0(0, "未知错误"),
        /**
         * HTTP Request 参数错误.
         */
        C_999(999, "HTTP Request 参数错误"),
    
        // ====================================================== //
        // client 错误码 1000 - 1999                               //
        // ====================================================== //
        /**
         * 未发现指定 client_id 客户端记录.
         */
        C_1000(1000, "未发现指定 client_id 客户端记录"),
        C_1001(1001, "client_secret 不匹配"),
    
        // ====================================================== //
        // user 错误码 2000 - 2999                                //
        // ====================================================== //
    
        /**
         * 未发现指定 email 的用户.
         */
        C_2000(2000, "未发现指定 email 的用户"),
        C_2011(2011, "password 不匹配"),
    
        //
        ;
    
        override fun toString(): String {
            return "[$code] $msg"
        }
    }
    
    class BizCodeException : RuntimeException {
    
        val bizCode: BizCode
    
        constructor(bizCode: BizCode) : super(bizCode.toString()) {
            this.bizCode = bizCode
        }
    
        constructor(bizCode: BizCode, e: Exception) : super(bizCode.toString(), e) {
            this.bizCode = bizCode
        }
    
        override fun fillInStackTrace() = this
    }

    回覆
    0
  • 女神的闺蜜爱上我

    女神的闺蜜爱上我2017-06-30 09:58:07

    說明的挺清楚了啊,方便捕獲處理

    回覆
    0
  • 扔个三星炸死你

    扔个三星炸死你2017-06-30 09:58:07

    Exception名字要有意義,RuntimeException名字沒有意義

    回覆
    0
  • 怪我咯

    怪我咯2017-06-30 09:58:07

    Exception直接拋的話,Nginx 會把你定義message 覆蓋掉,導致看不到具體資訊。
    建議的做法是,自己定義一個exception,去繼承 RuntimeException,這個就知道你的exception 是什麼,也方便找出問題。

    回覆
    0
  • typecho

    typecho2017-06-30 09:58:07

    運作時異常不需要捕捉

    回覆
    0
  • 取消回覆