防御性編程以及我的一些感想
By bxbxbai
防御性編程小例,最開始我是關注了這個人的微信,才看到這篇文章的,最近也工作了一段時間了~對自己以及別人寫的代碼有了一些新的想法(因為我遇到過很多坑啊囧)。因此,本文來談談這個話題。
在公司,我們碰到的很大一部分問題都是NullPointerException
。我常常就想:這段程序明明在我手機上運行好好的,為什么會出現這種情況呢?
因為,我們永遠都無法預測用戶使用 App 時會發生的各種情況。所以防御性編程可以讓我們減少很大一部分錯誤。
先說一個故事
先來說一個我去年面試過的問題,面試官問我:請你用最熟悉的語言寫一個 atoi 程序。
我心里一想:這么簡單!!我要好好寫!不要寫出 bug!我馬上就寫好了,并且用“12334”這種簡單的字符串試了又試,沒問題就交給他看。
public int atoi (String a){ int len = a.length (); int num = 0; for(int i = len - 1; i >= 0; i--) { num += (a.charAt (i) - '0') * Math.pow (10, len - i - 1); } return num; }
面試官一看就問我,你找找有什么問題沒,我看了好幾遍(我都在找 bug),說沒問題啊!我又仔細一想:如果傳進來一個負數怎么辦呢?比如“-12333”,這段程序就錯了!
我就和面試官說了~他說嗯,還有問題嗎?我心里想還有啊?想了幾遍都想不出!我說:效率問題?他不給面子直接就說:你先別管效率!
他說如果我傳進來一個null
會怎么樣?我恍然大悟!!!我有太多東西沒考慮到(我圖樣圖森破啊囧!!)!
上面就是我的一個真實的故事~不知你看了有什么感想,反正我覺得這次面試可以讓我反思很多我存在的問題。
自從看了前面提到的那篇文章后,我現在寫代碼就時刻裝著“防御性編程”這 5 個字。
那么怎么寫防御性代碼呢?
請看Integer.parseInt (String)
這個方法,好好看!我現在分析一下~JDK 的大神們怎么寫健壯的代碼!(如果有錯誤請指正~ =.=)
public static int parseInt (String string, int radix) throws NumberFormatException { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) { throw new NumberFormatException ("Invalid radix: " + radix); } if (string == null) { throw invalidInt (string); } int length = string.length (), i = 0; if (length == 0) { throw invalidInt (string); } boolean negative = string.charAt (i) == '-'; if (negative && ++i == length) { throw invalidInt (string); }return parse (string, i, radix, negative);
}</pre>
上面這段代碼出自 java 1.7.0_51 的
java.lang.Integer
類,JDK 開發大神是如何寫代碼的呢?可以看到這段代碼最開始的一部分就是在驗證每個參數的正確性(代碼中 radix 表示進制數),這里最小的進制就是2,最大進制是 36。如果進制數不滿足要求,直接拋出異常。
然后判斷傳入字符串是否為
null
,如果字符串不為null
,然后可以取字符串的長度。 后面再判斷字符串是否一個負數, 當所有參數都驗證過了以后再做正事——將字符串轉換成一個數字。我現在得到的一個重要的經驗就是:
當你寫一個方法需要對傳入的參數進行處理或者計算的時候,你必須要嚴格驗證傳入參數的正確性,如果不符合,就應當給出提示!
上面提到的那篇文章里說到:
這就是防御性編程的最基本規則:保護程序免遭非法輸入數據的破壞。
</blockquote>這些都是我以前編程不會考慮的事情啊!
如果你的代碼沒有防御性措施,那么你一定會遇到各種坑的~只是時候未到~
但也不是說所有的程序都應該這么寫。如果你在寫一個 private 方法只供類里面使用,那么我覺得就不必寫這種防御性代碼了。當然沒有絕對的事情,如果一個 public 方法接受外部傳入的參數,這個參數又傳入這個 private 方法,那么你在使用這個 private 方法時候就需要先驗證參數的合法性,然后再調用這個 private 方法。
當你在寫一個 public 方法可以接受來自任何地方的參數時,就必須要驗證參數的合法性了!
那么為什么要防御性編程
我覺得最終的目的就是為了讓你寫的代碼正確運行,當面對各種各樣的參數時,同時要向外部提供參數錯誤的原因,可以快速找到 bug。
在 Android 開發里面,主線程(UI 線程)中的一個微小的問題都會導致程序的崩潰,可能是一不小心一個 View 對象傳入某個方法的時候是一個
null
,也可能一個方法的返回值是null
等等,各種坑會在隱藏的地方等著你來踩哦~要知道當一個對象為
null
的時候(你肯定不知道它為null
),然后調用它的方法時,就會發生程序崩潰,這是應該是程序崩潰最常見的原因之一了~比如在我最開始寫的那個 atoi 程序里,如果別人用我的程序不小心傳入一個
null
,那么我的程序就崩潰了~本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!