小酌重構系列[20]——用條件判斷代替異常


概述

異常處理的關鍵在於何時處理異常以及如何使用異常,有些開發者會覺得try catch的處理和使用難以把握,於是他們秉承着“您可錯殺一千,不可放過一個”的想法,給所有的方法添加try catch。

這種方式會對應用程序造成什么影響嗎?

從用戶角度出發,用戶確實難以察覺到什么,應用程序運行正常,使用的體驗好像也沒什么差別。

從程序角度出發,大量的try catch會降低代碼的可讀性,只有在異常觸發時才會對程序的性能造成較大的影響。

這兩種角度有對錯嗎?

二者都沒有錯,第一種角度甚至要遠遠高於第二種角度。

對於程序員來說,寫程序開發產品的最終目的不是為了在技術上吹毛求疵,而是為了滿足市場和用戶的業務需求,用戶並不關心產品的內部實現——用戶覺得好的產品,是真正的好產品。

我們不必糾結於這兩種角度的處理方式,適合自己的才是最佳的。

但是一些場景下確實不宜使用try catch

  1. 流程控制語句:流程控制有它本身的邏輯,我們應該用判斷來規避try catch語句塊的使用
  2. 循環控制語句:一次catch對性能的影響是較小的,但在循環中卻可以積少成多,因此可能會產生較大的性能損失。

本文的主題“用條件判斷代替異常”是針對場景1的,當使用try catch來控制程序流程時,如果程序中不存在“危險”代碼(例如:類型轉換、建立連接等),就沒有必要使用try catch,我們可以直接使用條件判斷來控制程序流程。

異常不發生的時候,只是給程序套了一層try{}語句塊,對性能的影響微乎其微。
當異常發生的時候,進入catch語句塊,CLR需要創建異常對象,保存堆棧信息,逐層查找異常表,這會較大地影響程序的性能。

異常處理是一個較大的課題,也是程序設計的一個橫切關注點,本文不會對此進行深入的說明。

示例

重構前

下面這段代碼表示“微波爐當前如果沒有被使用,那么我們就可以用它加熱食物”。

public class Microwave
{
    private IMicrowaveMotor Motor { get; set; }

    public bool Start(object food)
    {
        bool foodCooked = false;
        try
        {
            Motor.Cook(food);
            foodCooked = true;
        }
        catch (InUseException)
        {
            foodcooked = false;
        }

        return foodCooked;
    }
}

這段代碼通過是否觸發自定義異常InUseException,來決定方法Start()方法的返回值,這是典型的使用try catch語句塊來控制流程的做法。

catch語句塊捕獲了InUseException,卻沒有處理InUseException,這不僅損失了程序的性能,也未體現自定義異常InUseException的價值。
這僅僅是一個常見的邏輯判斷,我們用條件判斷就可以了。

重構后

重構以后,代碼的可讀性增強了,還消除了捕捉異常帶來的性能損失。

public class Microwave
{
    private IMicrowaveMotor Motor { get; set; }

    public bool Start(object food)
    {
        if (Motor.IsInUse)
            return false;

        Motor.Cook(food);

        return true;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM