軟件構(gòu)造|學(xué)習(xí)心得01 靜態(tài)檢查

目標(biāo):

? 學(xué)習(xí)靜態(tài)系列

? 了解好的軟件的三大特性

冰雹序列

? “冰雹序列”的定義:從正整數(shù)n開(kāi)始票摇,如果n是偶數(shù),則下一個(gè)數(shù)是n/2精置,否則下一個(gè)數(shù)是3n+1都弹,直到n等于1娇豫。

這里有幾個(gè)例子:


由于存在3n+1這種變化,所以序列元素的大小可能會(huì)忽高忽低——這也是“冰雹序列”名稱(chēng)的來(lái)歷畅厢,冰雹在落地前會(huì)在云層中忽上忽下。那么所有的序列都會(huì)最終“落地”變到1嗎氮昧?(這個(gè)猜想稱(chēng)為考拉茲猜想框杜。)

計(jì)算冰雹序列

下面的代碼用于打印冰雹序列:


Java實(shí)現(xiàn)


Python實(shí)現(xiàn)

在語(yǔ)法中Java和Python的區(qū)別:

? Java中表達(dá)式和語(yǔ)句的基本語(yǔ)義與Python非常相似:例如while,if行為相同袖肥。

? Java需要以分號(hào)結(jié)尾咪辱。額外的標(biāo)點(diǎn)符號(hào)看著很麻煩,實(shí)際上它也提供了更多組織代碼的自由——例如可以將語(yǔ)句分成多行椎组。

? Java在使用 if 和 while的時(shí)需要用括號(hào)括起來(lái)油狂。

? Java需要在塊周?chē)褂没ɡㄌ?hào)。即使Java不會(huì)對(duì)多余的空間給予任何關(guān)注寸癌,也應(yīng)始終縮進(jìn)該塊专筷。編程是一種交流形式,您不僅在與編譯器交流蒸苇,還與人類(lèi)交流磷蛹。

數(shù)據(jù)類(lèi)型

?? Python和Java最大的不同就是Java需要指定變量n的類(lèi)型:int類(lèi)型是一些值的集合,以及這些值對(duì)應(yīng)的操作溪烤。

例如下面這5種常用的原始類(lèi)型 :

int (例如5和-200這樣的整數(shù)味咳,但是其范圍有限制但在2^31之間,大概在±20億)

long (比int更大范圍的整數(shù)檬嘀,大概至2^63)

boolean(true和false)

double (浮點(diǎn)數(shù)槽驶,其表示的是實(shí)數(shù)的子集)

char (單個(gè)字符例如 ‘A’ 和 ‘$’)

Java也有對(duì)象類(lèi)型 ,例如:

String 表示一串連續(xù)的字符鸳兽。

BigInteger 表示任意大小的整數(shù)掂铐。

? ?? 從Java的傳統(tǒng)來(lái)說(shuō),原始類(lèi)型用小寫(xiě)字母贸铜,對(duì)象類(lèi)型的起始字母用大寫(xiě)堡纬。

? ? 操作符是一些能接受輸入并輸出結(jié)果的功能。他們的語(yǔ)法各有區(qū)別蒿秦,Java中常見(jiàn)的有下面這三種:

?前綴烤镐、中綴、后綴操作符. 例如棍鳖, a + b 調(diào)用這樣一種操作(映射) + : int × int → int( + 是這個(gè)操作符的名字, int × int 描述了這兩個(gè)輸入, 最后的 int 描述的了輸出)

? 一個(gè)對(duì)象的方法. 例如炮叶, bigint1.add(bigint2) 調(diào)用這樣一種操作(映射) add: BigInteger × BigInteger → BigInteger.

? 一個(gè)函數(shù). 例如: Math.sin(theta) 調(diào)用這樣一種操作(映射) sin: double → double. 注意碗旅, Math 不是一個(gè)對(duì)象,它是一個(gè)包含sin函數(shù)的類(lèi)镜悉。

? ? 有一些操作符可以對(duì)不同類(lèi)型的對(duì)象進(jìn)行操作祟辟,這時(shí)我們就稱(chēng)之為可重載 (overloaded),例如Java中的算術(shù)運(yùn)算符 +, -, *, / 都是可重載的侣肄。一些函數(shù)也是可重載的旧困。大多數(shù)編程語(yǔ)言都有不容程度的重載性。

靜態(tài)類(lèi)型

? ? Java是一種靜態(tài)類(lèi)型的語(yǔ)言稼锅。所有變量的類(lèi)型在編譯的時(shí)候就已經(jīng)知道了(程序還沒(méi)有運(yùn)行)吼具,所以編譯器也可以推測(cè)出每一個(gè)表達(dá)式的類(lèi)型。

例如矩距,如果a和b是int類(lèi)型的拗盒,那么編譯器就可以知道a+b的結(jié)果也是int類(lèi)型的。事實(shí)上锥债,Eclipse編譯環(huán)境在寫(xiě)代碼時(shí)如果出錯(cuò)就會(huì)發(fā)現(xiàn)陡蝇。

動(dòng)態(tài)類(lèi)型 語(yǔ)言中(例如Python)中,這種類(lèi)型檢查是發(fā)生在程序運(yùn)行時(shí)哮肚。

靜態(tài)類(lèi)型 是靜態(tài)檢查的其中一種——這意味著在編譯時(shí)檢查bug登夫。靜態(tài)檢查是為了避免bug的發(fā)生。其中靜態(tài)類(lèi)型阻止了一大部分和類(lèi)型相關(guān)的bug—確切點(diǎn)說(shuō)绽左,就是將操作符用到了不對(duì)應(yīng)的類(lèi)型對(duì)象上悼嫉。例如,如果你進(jìn)行下面這個(gè)操作:


那么靜態(tài)類(lèi)型檢查就會(huì)在你編輯代碼的時(shí)候發(fā)現(xiàn)這個(gè)bug拼窥,而不是等到你編譯后運(yùn)行程序的時(shí)候告知你戏蔑。

靜態(tài)檢查、動(dòng)態(tài)檢查鲁纠、無(wú)檢查

編程語(yǔ)言通常能提供以下三種自動(dòng)檢查的方法:

? 靜態(tài)檢查:bug在程序還沒(méi)有被執(zhí)行的時(shí)候被自動(dòng)地檢查出來(lái)

? 動(dòng)態(tài)檢查:bug在程序正在被執(zhí)行的時(shí)候被發(fā)現(xiàn)

? 無(wú)檢查: 編程語(yǔ)言本身不幫助你發(fā)現(xiàn)錯(cuò)誤总棵,你必須通過(guò)特定的條件(例如輸出的結(jié)果)檢查代碼的正確性。

? 相比較而言改含,靜態(tài)檢查好于動(dòng)態(tài)檢查好于不檢查情龄。

? ? 下面是一些各種類(lèi)型的檢查能檢查出來(lái)的錯(cuò)誤:

靜態(tài)檢查:

?語(yǔ)法錯(cuò)誤例如多余的標(biāo)點(diǎn)符號(hào)或者錯(cuò)誤的關(guān)鍵詞。即使在動(dòng)態(tài)類(lèi)型的語(yǔ)言例如Python中也會(huì)做這種檢查:如果你有一個(gè)多余的縮進(jìn)捍壤,在運(yùn)行之前就能發(fā)現(xiàn)它骤视。

? 錯(cuò)誤的名字例如Math.sine(2). (修正:應(yīng)該是 sin.)

? 錯(cuò)誤的參數(shù)個(gè)數(shù):例如 Math.sin(30, 20).

? 錯(cuò)誤的參數(shù)類(lèi)型: Math.sin(“30”).

? 錯(cuò)誤的返回類(lèi)型 :例如一個(gè)聲明返回int類(lèi)型函數(shù)return “30”;

動(dòng)態(tài)檢查:

? 非法的變量值:例如整型變量x、y鹃觉,表達(dá)式x/y 只有在運(yùn)行后y為0才會(huì)報(bào)錯(cuò)专酗,否則就是正確的。因此盗扇,在這個(gè)表達(dá)式中除以0不是一個(gè)靜態(tài)錯(cuò)誤而是一個(gè)動(dòng)態(tài)錯(cuò)誤祷肯。

? 無(wú)法表示的返回值:例如最后得到的返回值無(wú)法用聲明的類(lèi)型來(lái)表示沉填。

? 越界訪問(wèn)例如在一個(gè)字符串中使用一個(gè)負(fù)數(shù)索引。

? 使用一個(gè)null對(duì)象解引用:(null相當(dāng)于Python中的None)

? ? ? 靜態(tài)檢查傾向于類(lèi)型錯(cuò)誤 佑笋,即與特定的值無(wú)關(guān)的錯(cuò)誤翼闹。正如上面提到過(guò)的,一個(gè)類(lèi)型是一系列值的集合蒋纬,而靜態(tài)類(lèi)型就是保證變量的值在這個(gè)集合中猎荠,但是在運(yùn)行前我們可能不會(huì)知道這個(gè)值的結(jié)果到底是多少。所以如果一個(gè)錯(cuò)誤必須要特定的值來(lái)“觸發(fā)”(例如除零錯(cuò)誤和越界訪問(wèn))颠锉,編譯器是不會(huì)在編譯的時(shí)候報(bào)錯(cuò)的法牲。

? ? ? 與此相對(duì)的,動(dòng)態(tài)類(lèi)型檢查傾向于特定值才會(huì)觸發(fā)的錯(cuò)誤琼掠。

原始類(lèi)型并不是真正的數(shù)

? ? ? 在Java和許多其他語(yǔ)言中存在一個(gè)“陷阱”即原始數(shù)據(jù)類(lèi)型的對(duì)象在有些時(shí)候并不像真正的數(shù)字那樣得到應(yīng)有的輸出。結(jié)果就是本來(lái)應(yīng)該被動(dòng)態(tài)檢查發(fā)現(xiàn)的錯(cuò)誤沒(méi)有報(bào)錯(cuò)停撞。例如:

? 整數(shù)的除法:5/2并不會(huì)返回一個(gè)小數(shù)瓷蛙,而是一個(gè)去掉小數(shù)部分的整數(shù)對(duì)象,因?yàn)槌ú僮鞣麑?duì)兩個(gè)整數(shù)對(duì)象運(yùn)算后的結(jié)果還是整數(shù)戈毒,而整數(shù)對(duì)象是無(wú)法表示5/2的精確值的(而我們期望它會(huì)是一個(gè)動(dòng)態(tài)檢查能發(fā)現(xiàn)的錯(cuò)誤)艰猬。

? 整型溢出: int 和 long類(lèi)型的值的集合是一個(gè)有限集合——它們有最大的值和最小的值,當(dāng)運(yùn)算的結(jié)果過(guò)大或者過(guò)小的時(shí)候我們就很可能得到一個(gè)在合法范圍內(nèi)的錯(cuò)誤值埋市。

? 浮點(diǎn)類(lèi)型中的特殊值:在浮點(diǎn)類(lèi)型例如double中有一些不是數(shù)的特殊值:NaN ( “Not a Number”), POSITIVE_INFINITY (正無(wú)窮), and NEGATIVE_INFINITY (負(fù)無(wú)窮).當(dāng)你對(duì)浮點(diǎn)數(shù)進(jìn)行運(yùn)算的時(shí)候可能就會(huì)得到這些特殊值(例如除零或者對(duì)一個(gè)負(fù)數(shù)開(kāi)更號(hào))冠桃,如果你拿著這些特殊值繼續(xù)做運(yùn)算,那你可能就會(huì)得到一個(gè)意想不到結(jié)果(譯者注:例如拿NaN和別的數(shù)進(jìn)行比較操作永遠(yuǎn)是False) 道宅。

閱讀小練習(xí)

讓我們嘗試一些錯(cuò)誤代碼的示例食听,看看它們?cè)贘ava中的行為。這些錯(cuò)誤是靜態(tài)污茵,動(dòng)態(tài)還是根本不捕獲的樱报?


靜態(tài)錯(cuò)誤


無(wú)報(bào)錯(cuò),但是得到錯(cuò)誤的結(jié)果


無(wú)報(bào)錯(cuò)泞当,但是得到錯(cuò)誤的結(jié)果



動(dòng)態(tài)錯(cuò)誤



無(wú)報(bào)錯(cuò)迹蛤,但是得到錯(cuò)誤的結(jié)果


數(shù)組和聚集類(lèi)型

? ? 讓我們把“冰雹序列”的結(jié)果存儲(chǔ)在數(shù)據(jù)結(jié)構(gòu)中而不僅僅是輸出。Java中有兩種常用的線性存儲(chǔ)結(jié)構(gòu):數(shù)組和列表襟士。

? ? 數(shù)組是一連串類(lèi)型相同的元素組成的結(jié)構(gòu)盗飒,而且它的長(zhǎng)度是固定的(元素個(gè)數(shù)固定)。例如陋桂,我們聲明一個(gè)整型數(shù)組變量:

對(duì)于數(shù)組逆趣,常用的操作符有下:

? 索引其中的一個(gè)元素: a[2]

? 賦予一個(gè)元素特定的值: a[2]=0

? 求數(shù)組長(zhǎng)度: a.length (和 String.length() 的區(qū)別—— a.length 不是一個(gè)類(lèi)內(nèi)方法調(diào)用,所以不能在它后面寫(xiě)上括號(hào)和參數(shù))

下面是我們利用數(shù)組寫(xiě)的第一個(gè)求“冰雹序列”的代碼章喉,它存在一些bug:



? ? ? 相信很快你就能發(fā)現(xiàn)錯(cuò)誤:數(shù)組的長(zhǎng)度是100(100稱(chēng)為幻數(shù))汗贫?如果我們嘗試的n的冰雹序列長(zhǎng)到大于100的話就無(wú)法使用這個(gè)數(shù)組身坐。假如我們犯了錯(cuò)誤,Java是否能夠靜態(tài)地落包、動(dòng)態(tài)地檢查出這個(gè)錯(cuò)誤或者根本不檢查部蛇?偶然地,像這樣一個(gè)固定長(zhǎng)度的數(shù)組的溢出在像C或者C++這樣不太安全的語(yǔ)言中是非常常見(jiàn)的咐蝇,而且被稱(chēng)為緩沖區(qū)溢出涯鲁。這種溢出是大量網(wǎng)絡(luò)安全漏洞和網(wǎng)絡(luò)爬蟲(chóng)的罪魁禍?zhǔn)住?/p>

集合類(lèi)型

? ? ? 解決方法是使用List類(lèi)型。List類(lèi)型而不是固定長(zhǎng)度的數(shù)組有序。我們可以這樣聲明列表:



常用的操作符有下:

? 索引一個(gè)元素: list.get(2)

? 賦予一個(gè)元素特定的值: list.set(2, 0)

? 求列表的長(zhǎng)度: list.size()

? ? ? 這里要注意List是一個(gè)接口抹腿,這種類(lèi)型的對(duì)象無(wú)法直接用new來(lái)構(gòu)造,必須用能夠?qū)崿F(xiàn)List要求滿足的操作符的方法來(lái)構(gòu)造旭寿。我們會(huì)在后來(lái)講抽象數(shù)據(jù)類(lèi)型的時(shí)候具體將價(jià)格這個(gè)警绩。ArrayList是一個(gè)實(shí)類(lèi)型的類(lèi),它提供了List操作符的具體實(shí)現(xiàn)盅称。ArrayList不是唯一的實(shí)現(xiàn)方法肩祥,但是是最常用的一個(gè)。在Java API的文檔里找到很多這方面的信息缩膝。另外要注意的是混狠,我們寫(xiě)的是List< Integer >而不是List< int>,不幸的是我們不能直接模仿int[]那樣寫(xiě)List< int>。List只知道如何處理對(duì)象類(lèi)型疾层,而不知道原始類(lèi)型将饺。在Java中,每個(gè)原語(yǔ)類(lèi)型(它們是用小寫(xiě)寫(xiě)的痛黎,通常是縮寫(xiě)的予弧,比如int)都有一個(gè)等效的對(duì)象類(lèi)型(這個(gè)對(duì)象類(lèi)型是大寫(xiě)的,并且拼寫(xiě)完整舅逸,就像Integer一樣)桌肴。Java要求我們?cè)趨?shù)化帶有尖括號(hào)的類(lèi)型時(shí)使用這些對(duì)象類(lèi)型等價(jià)物。但是在其他情況下琉历,Java會(huì)自動(dòng)在int和Integer之間進(jìn)行轉(zhuǎn)換坠七,因此我們可以編寫(xiě)Integer i=5,而不會(huì)出現(xiàn)任何類(lèi)型錯(cuò)誤旗笔。

下面是用列表編寫(xiě)的“冰雹序列”的實(shí)現(xiàn):



這樣實(shí)現(xiàn)除了看起來(lái)簡(jiǎn)潔而且更加安全彪置,因?yàn)榱斜頃?huì)自動(dòng)擴(kuò)充它自己以滿足新添加的元素(當(dāng)然,直到你的內(nèi)存不夠用為止)

迭代

? ? ? 對(duì)于在一個(gè)序列結(jié)構(gòu)(例如列表和數(shù)組)遍歷元素蝇恶,Java和Python的寫(xiě)法差不多:



? ? ? Math.max() 是一個(gè)Java API提供的方便的函數(shù)拳魁。

方法

? ? ? 在Java中,聲明通常必須在一個(gè)方法中撮弧,而每個(gè)方法都要在一個(gè)類(lèi)型中潘懊,所以寫(xiě)“冰雹序列”程序最簡(jiǎn)單可以這么寫(xiě):



public姚糊、private、static

? ? ? ? public意味著任何在你程序中的代碼都可以訪問(wèn)這個(gè)類(lèi)或者方法授舟。其他的類(lèi)型修飾符救恨,例如private ,是用來(lái)確保程序的安全性的——它保證了可變類(lèi)型不會(huì)被別處的代碼所修改释树。我們會(huì)在后面的課程中詳細(xì)提到肠槽。

? ? ?? ? static意味這這個(gè)方法沒(méi)有self這個(gè)參數(shù)——Java會(huì)隱含的實(shí)現(xiàn)它,所以你不會(huì)看到這個(gè)參數(shù)奢啥。靜態(tài)的方法不能通過(guò)對(duì)象來(lái)調(diào)用秸仙,例如List add() 方法 或者 String length()方法,它們要求先有一個(gè)對(duì)象桩盲。靜態(tài)方法的正確調(diào)用應(yīng)該使用類(lèi)來(lái)索引寂纪,例如:



? ? ? 另外,記得在定義的方法前面寫(xiě)上注釋赌结。這些注釋?xiě)?yīng)該描述了這個(gè)方法的功能弊攘,輸入輸出/返回,以及注意事項(xiàng)姑曙。記住注釋不要寫(xiě)的啰嗦,而是應(yīng)該直切要點(diǎn)迈倍,簡(jiǎn)潔明了伤靠。例如在上面的代碼中,n是一個(gè)整型的變量啼染,這個(gè)在聲明的時(shí)候int已經(jīng)體現(xiàn)出來(lái)了宴合,就不需要進(jìn)行注釋。但是如果我們?cè)O(shè)想的本意是n不能為負(fù)數(shù)迹鹅,而這個(gè)編譯器(聲明)是不能檢查和體現(xiàn)出來(lái)的卦洽,我們就應(yīng)該注釋出來(lái),方便閱讀理解和修改斜棚。

? ? ? 這些東西我們會(huì)在后面的課程中詳細(xì)介紹阀蒂,但是你現(xiàn)在就要開(kāi)始試著正確使用他們。

變化的值vs.可被賦值的改變

? ? ? 我們會(huì)介紹“快照?qǐng)D”(snapshot diagrams)弟蚀,以此來(lái)辨別修改一個(gè)變量和修改一個(gè)值的區(qū)別蚤霞。當(dāng)你給一個(gè)變量賦值的時(shí)候,你實(shí)際上是在改變這個(gè)變量指向的對(duì)象(值也不一樣)义钉。

? ? ? 而當(dāng)你對(duì)一個(gè)可變的值進(jìn)行賦值操作的時(shí)候——例如數(shù)組或者列表——你實(shí)際上是在改變對(duì)象本身的內(nèi)容昧绣。

? ? ? 變化是“邪惡”的,好的程序員會(huì)避免可改變的東西捶闸,因?yàn)檫@些改變可能是意料之外的夜畴。

? ? ? 不變性(Immutability)是我們這門(mén)課程的一個(gè)重要設(shè)計(jì)原則拖刃。不變類(lèi)型是指那些這種類(lèi)型的對(duì)象一旦創(chuàng)建其內(nèi)容就不能被更改的類(lèi)型(至少外部看起來(lái)是這樣,我們?cè)诤竺娴牡恼n程中會(huì)說(shuō)一些替代方案)贪绘。思考一下在上面的代碼中哪一些類(lèi)型是可更改類(lèi)型兑牡,哪一些不是?(例如int就是不變的兔簇,List就是可變的发绢,給int類(lèi)型的對(duì)象賦值就會(huì)讓它指向一個(gè)新的對(duì)象)

? ? ?? Java也給我們提供了不變的索引:只要變量被初始化后就不能再次被賦值了——只要在聲明的時(shí)候加上final :



? ? ? 如果編譯器發(fā)現(xiàn)你的final變量不僅僅是在初始化的時(shí)候被“賦值”,那么它就會(huì)報(bào)錯(cuò)垄琐。換句話說(shuō)边酒,final會(huì)提供不變索引的靜態(tài)檢查。

? ? ? 正確的使用final是一個(gè)好習(xí)慣狸窘,就好像類(lèi)型聲明一樣墩朦,這不僅會(huì)讓編譯器幫助你做靜態(tài)檢查,同時(shí)別人讀起來(lái)也會(huì)更順利一些翻擒。

? ? ? 在hailstoneSequence方法中有兩個(gè)變量n和list氓涣,我們可以將它們聲明為final嗎?請(qǐng)說(shuō)明理由陋气。(譯者注:n不行劳吠,list可以。因?yàn)槲覀冃枰淖僴指向的對(duì)象巩趁,而List對(duì)象本身是可以更改的痒玩,我們也不需要改變list對(duì)應(yīng)的對(duì)象)



記錄設(shè)想

? ? ? 在文檔中寫(xiě)下變量的類(lèi)型記錄了一個(gè)關(guān)于它的設(shè)想, 例如這個(gè)變量總是指向一個(gè)整型. 在編譯的時(shí)候 Java 就會(huì)檢查這個(gè)設(shè)想, 并且保證在你的代碼中沒(méi)有任何一處違背這個(gè)設(shè)想。

? ? ? 而使用 final 關(guān)鍵字去定義一個(gè)變量也是一種記錄設(shè)想, 要求這個(gè)變量在其被賦值之后就永遠(yuǎn)不會(huì)再被修改, Java 也會(huì)對(duì)其進(jìn)行靜態(tài)地檢查议慰。

? ? ? 不幸的是 Java 并不會(huì)自動(dòng)檢查所有設(shè)想蠢古,例如:n 必須為正數(shù)。

? ? ? 為什么我們需要寫(xiě)下我們的設(shè)想呢? 因?yàn)榫幊叹褪遣粩嗟脑O(shè)想, 如果我們不寫(xiě)下他們, 就可能會(huì)遺忘掉他們, 而且如果以后別人想要閱讀或者修改我們的軟件, 他們就會(huì)很難理解代碼, 不得不去猜測(cè)(譯者注: 變量的含義/函數(shù)的描述/返回值描述等等)

所以在編程的時(shí)候我們必須朝著如下兩個(gè)目標(biāo)努力:

? 與計(jì)算機(jī)交流. 首先說(shuō)服編譯器你的程序語(yǔ)法正確并且類(lèi)型正確, 然后保證邏輯正確, 這樣就可以讓它在運(yùn)行的時(shí)候給我們正確的結(jié)果别凹。

? 與其他人交流. 盡可能使你的程序易于理解, 所以當(dāng)有人想要在將來(lái)某些時(shí)候修正它, 改進(jìn)它或者對(duì)其進(jìn)行適配的時(shí)候, 他們可以很方便地實(shí)現(xiàn)自己的想法草讶。

黑客派(Hacking)vs.工程派(Engineering)

? ? 黑客派 的編程風(fēng)格可以理解為“放飛自我并且樂(lè)觀的”(貶義):

? 缺點(diǎn): 在已經(jīng)編寫(xiě)大量代碼以后才測(cè)試它們

? 缺點(diǎn): 將所有的細(xì)節(jié)都放在腦子里, 以為自己可以永遠(yuǎn)記住所有的代碼, 而不是將它們編寫(xiě)在代碼中

? 缺點(diǎn): 認(rèn)為 BUG 都不存在或者它們都非常容易發(fā)現(xiàn)和被修復(fù).

工程派 對(duì)應(yīng)的做法是(褒義):

? 優(yōu)點(diǎn): 一次只寫(xiě)一點(diǎn)點(diǎn), 一邊寫(xiě)一邊測(cè)試. 在將來(lái)的課程中, 我們將會(huì)探討"測(cè)試優(yōu)先編程" (test-first programming)

? 優(yōu)點(diǎn): 記錄代碼的設(shè)想、意圖 (document the assumptions that your code depends on)

? 優(yōu)點(diǎn): 靜態(tài)代碼檢查將會(huì)保護(hù)你的代碼不淪為“愚蠢的代碼”

本課程的目標(biāo)

本門(mén)課程的主要目標(biāo)為學(xué)習(xí)如何生產(chǎn)具有如下屬性的軟件:

? 遠(yuǎn)離bug 正確性 (現(xiàn)在看起來(lái)是正確的), 防御性 (將來(lái)也是正確的)

? 易讀性 我們不得不和以后有可能需要理解和修改代碼的程序員進(jìn)行交流 (修改 BUG 或者添加新的功能), 那個(gè)將來(lái)的程序員或許會(huì)是幾個(gè)月或者幾年以后的你, 如果你不進(jìn)行交流, 那么到了那個(gè)時(shí)候, 你將會(huì)驚訝于你居然忘記了這么多, 并且這將會(huì)極大地幫助未來(lái)的你有一個(gè)良好的設(shè)計(jì)炉菲。

? 可改動(dòng)性. 軟件總是在更新迭代的, 一些好的設(shè)計(jì)可以讓這個(gè)過(guò)程變得非常容易, 但是也有一些設(shè)計(jì)將會(huì)需要讓開(kāi)發(fā)者扔掉或者重構(gòu)大量的代碼堕战。

? ? ? 軟件還有其他重要屬性(如性能,可用性颁督,安全性)践啄,它們可能會(huì)與這三個(gè)屬性相抵觸。但是沉御,這些是我們?cè)诒敬握n程中關(guān)注的三大巨頭屿讽,并且軟件開(kāi)發(fā)人員通常將其放在構(gòu)建軟件的實(shí)踐中。值得考慮的是我們?cè)诒菊n程中學(xué)習(xí)的每種語(yǔ)言功能,每種編程實(shí)踐伐谈,每種設(shè)計(jì)模式烂完,并了解它們與三巨頭的關(guān)系。

總結(jié)

我們今天主要介紹的思想為靜態(tài)代碼檢查, 下面是該思想和我們課程目標(biāo)的關(guān)系:

? 幫助我們遠(yuǎn)離bug? 靜態(tài)代碼檢查可以通過(guò)捕捉類(lèi)型錯(cuò)誤等其他BUG幫助我們?cè)谶\(yùn)行代碼之前就發(fā)現(xiàn)它們

? 易讀性? 它可以幫助我們理解, 因?yàn)樗械念?lèi)型在代碼中被明確定義 (譯者注: 相比于 Python/PHP 這類(lèi)動(dòng)態(tài)變量類(lèi)型的語(yǔ)言)

? 可改動(dòng)性? 靜態(tài)代碼檢查可以在你在修改你的代碼的時(shí)候定位出也需要被修改的地方, 例如: 當(dāng)你改變一個(gè)變量的類(lèi)型或者名稱(chēng)的時(shí)候, 編譯器立即就會(huì)在所有使用到這個(gè)變量的地方顯示錯(cuò)誤, 提示你也需要更新它們诵棵。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抠蚣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子履澳,更是在濱河造成了極大的恐慌嘶窄,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件距贷,死亡現(xiàn)場(chǎng)離奇詭異柄冲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)手趣,“玉大人,你說(shuō)我怎么就攤上這事戒祠。” “怎么了速种?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵姜盈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我配阵,道長(zhǎng)贩据,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任闸餐,我火速辦了婚禮,結(jié)果婚禮上矾芙,老公的妹妹穿的比我還像新娘舍沙。我一直安慰自己,他們只是感情好剔宪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布拂铡。 她就那樣靜靜地躺著,像睡著了一般葱绒。 火紅的嫁衣襯著肌膚如雪感帅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天地淀,我揣著相機(jī)與錄音失球,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛实苞,可吹牛的內(nèi)容都是我干的豺撑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼黔牵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼聪轿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起猾浦,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤陆错,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后金赦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體音瓷,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年素邪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了外莲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兔朦,死狀恐怖偷线,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沽甥,我是刑警寧澤声邦,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站摆舟,受9級(jí)特大地震影響亥曹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恨诱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一媳瞪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧照宝,春花似錦蛇受、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至剂碴,卻和暖如春把将,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忆矛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工察蹲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓递览,卻偏偏與公主長(zhǎng)得像叼屠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绞铃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355