日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

麻省理工18年春软件构造课程阅读06“规格说明”

發(fā)布時(shí)間:2023/12/10 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 麻省理工18年春软件构造课程阅读06“规格说明” 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文內(nèi)容來自MIT_6.031_sp18: Software Construction課程的Readings部分,采用CC BY-SA 4.0協(xié)議。

由于我們學(xué)校(哈工大)大二軟件構(gòu)造課程的大部分素材取自此,也是推薦的閱讀材料之一,于是打算做一些翻譯工作,自己學(xué)習(xí)的同時(shí)也能幫到一些懶得看英文的朋友。另外,該課程的閱讀資料中有許多練習(xí)題,但是沒有標(biāo)準(zhǔn)答案,所給出的答案均為譯者所寫,有錯誤的地方還請指出。




譯者:李秋豪

審校:

V1.0 Tue Mar 13 22:17:35 CST 2018


本次課程的目標(biāo)

  • 理解方法規(guī)格說明中的前置條件和后置條件,并能夠?qū)懗稣_的規(guī)格說明
  • B能夠針對規(guī)格說明寫出測試
  • 理解Java中的檢查異常和非檢查異常(checked and unchecked exceptions)
  • 理解如何用異常處理特殊的結(jié)果

概要

規(guī)格說明是團(tuán)隊(duì)合作中的關(guān)鍵點(diǎn)。如果沒有規(guī)格說明,就沒有辦法分工實(shí)現(xiàn)各種方法。規(guī)格說明就像一份合同:實(shí)現(xiàn)者的義務(wù)在于滿足合同的要求,客戶可以依賴這些要求工作。事實(shí)上,我們會發(fā)現(xiàn)就像真的合同一樣,規(guī)格說明對雙方都有制約:當(dāng)合同上有前置條件時(shí),客戶有責(zé)任滿足這些條件。

在這篇閱讀材料中我們會研究方法中的規(guī)格說明,討論前置條件和后置條件分別是什么,它們對方法的實(shí)現(xiàn)者和使用者來說意味著什么。我們也會討論如何使用異常——Java、Python、以及很多現(xiàn)代語言中的一個(gè)重要特性,它使得方法的接口更加安全也更加易懂。


為什么要使用規(guī)格說明

在編程中,很多讓人抓狂的bug是由于兩個(gè)地方的代碼對于接口行為的理解不一樣。雖然每一個(gè)程序員在心里都有一份“規(guī)格說明”,但是不是所有程序員都會把他們寫下來。最終,一個(gè)團(tuán)隊(duì)中的不同程序員對于同一個(gè)接口就有不同的“規(guī)格說明”了。當(dāng)程序崩潰的時(shí)候,就很難發(fā)現(xiàn)問題在哪里。簡潔準(zhǔn)確的的規(guī)格說明使得我們遠(yuǎn)離bug,更可以快速發(fā)現(xiàn)問題所在。

規(guī)格說明對使用者(客戶)來說也是很有用的,它們使得使用者不必去閱讀源碼。如果你還不相信閱讀規(guī)格說明比閱讀源碼更簡單易懂的話,看看下面這個(gè)標(biāo)準(zhǔn)的Java規(guī)格說明和它對應(yīng)的源碼,它是 BigInteger 中的一個(gè)方法:

API 文檔中的規(guī)格說明:

public BigInteger add(BigInteger val)Returns a BigInteger whose value is (this + val).Parameters: val - value to be added to this BigInteger.Returns: this + val

Java 8 中對應(yīng)的源碼:

if (val.signum == 0)return this; if (signum == 0)return val; if (val.signum == signum)return new BigInteger(add(mag, val.mag), signum);int cmp = compareMagnitude(val); if (cmp == 0)return ZERO; int[] resultMag = (cmp > 0 ? subtract(mag, val.mag): subtract(val.mag, mag)); resultMag = trustedStripLeadingZeroInts(resultMag);return new BigInteger(resultMag, cmp == signum ? 1 : -1);

可以看到,通過閱讀 BigInteger.add 的規(guī)格說明,客戶可以直接了解如何使用 BigInteger.add ,以及它的行為屬性。如果我們?nèi)ラ喿x源碼,我們就不得不看 BigInteger 的構(gòu)造體, compare-Magnitude, subtract以及trusted-StripLeadingZero-Ints 的實(shí)現(xiàn)——而這還僅僅只是開始。

另外,規(guī)格說明對于實(shí)現(xiàn)者也是很有好處的,因?yàn)樗鼈兘o了實(shí)現(xiàn)者更改實(shí)現(xiàn)策略而不告訴使用者的自由。同時(shí),規(guī)格說明可以限定一些特殊的輸入,這樣實(shí)現(xiàn)者就可以省略一些麻煩的檢查和處理,代碼也可以運(yùn)行的更快。

如上圖所示,規(guī)格說明就好像一道防火墻一樣將客戶和實(shí)現(xiàn)者隔離開。它使得客戶不必知道這個(gè)單元是如何運(yùn)行的(不必閱讀源碼),也使得實(shí)現(xiàn)者不必管這個(gè)單元會被怎么使用(因?yàn)榭蛻粢袷厍爸脳l件)。這種隔離造成了“解耦”(decoupling),客戶自己的代碼和實(shí)現(xiàn)者的代碼可以獨(dú)立發(fā)生改動,只要雙方都遵循規(guī)格說明對應(yīng)的制約。


行為等價(jià)

思考下面兩個(gè)方法的異同:

static int findFirst(int[] arr, int val) {for (int i = 0; i < arr.length; i++) {if (arr[i] == val) return i;}return arr.length; }static int findLast(int[] arr, int val) {for (int i = arr.length -1 ; i >= 0; i--) {if (arr[i] == val) return i;}return -1; }

當(dāng)然,這兩個(gè)方法的代碼是不同的,名字的含義也不一樣。為了判斷“行為等價(jià)”,我們必須判斷一個(gè)方法是否可以替換另一個(gè)方法,而程序的行為不發(fā)生改變。

除了代碼,它們的行為也不一樣:

  • 當(dāng)val找不到時(shí),fingFirst返回arr的長度而findLast返回-1;
  • 當(dāng)數(shù)組中有兩個(gè)val的時(shí)候,findFirst返回較小的那個(gè)索引,而findLast返回較大的那個(gè)。

但是當(dāng)val在數(shù)組中僅有一個(gè)的時(shí)候,這兩個(gè)方法的行為是一樣的。也只有在這種情況下,我們才可以將方法的實(shí)現(xiàn)在兩者中互換。

“行為等價(jià)”是對于“旁觀者”來說的——就是客戶。為了讓實(shí)現(xiàn)方法可以發(fā)生改動,我們就需要一個(gè)規(guī)格說明要求客戶遵守某一些制約/前置條件。

所以,我們的規(guī)格說明可能是這樣的:

static int find(int[] arr, int val) - requires:val occurs exactly once in arr - effects:returns index i such that arr[i] = val

閱讀小練習(xí)

Behave nicely

static int findFirst(int[] a, int val) {for (int i = 0; i < a.length; i++) {if (a[i] == val) return i;}return a.length; } static int findLast(int[] a, int val) {for (int i = a.length - 1 ; i >= 0; i--) {if (a[i] == val) return i;}return -1; }

假設(shè)客戶只關(guān)心val是否在a中出現(xiàn)了一次。在這種情況下,findFirst 和 findLast 的行為等價(jià)嗎?

Yes

Best behavior

現(xiàn)在來改變一下規(guī)格說明,假設(shè)客戶對返回值要求:

  • 如果val在a中,返回任何索引i ,使得a[i] == val 。
  • 否則,返回一個(gè)不在a索引范圍內(nèi)的整數(shù)j

在這種情況下,findFirst 和 findLast 的行為等價(jià)嗎?

Yes


規(guī)格說明的結(jié)構(gòu)

一個(gè)規(guī)格說明含有以下兩個(gè)“條款”:

  • 一個(gè)前置條件,關(guān)鍵詞是requires
  • 一個(gè)后置條件,關(guān)鍵詞是effects

其中前置條件是客戶的義務(wù)(誰調(diào)用的這個(gè)方法)。它確保了方法被調(diào)用時(shí)所處的狀態(tài)。

而后置條件是實(shí)現(xiàn)者的義務(wù)。如果前置條件得到了滿足,那么該方法的行為應(yīng)該符合后置條件的要求,例如返回一個(gè)合適的值,拋出一個(gè)特定的異常,修改一個(gè)特定的對象等等。

如果前置條件不滿足的話,實(shí)現(xiàn)也不需要滿足后置條件——方法可以做任何事情,例如不終止而是拋出一個(gè)異常、返回一個(gè)任意的值、做一個(gè)任意的修改等等。

閱讀小練習(xí)

Logical implication

思考下面這個(gè)規(guī)格說明

static int find(int[] arr, int val) - requires:val occurs exactly once in arr - effects:returns index i such that arr[i] = val

作為find的實(shí)現(xiàn)者,下面哪些行為是合法的?

  • [x] 如果arr為空,返回0

  • [x] 如果arr為空,拋出一個(gè)異常

  • [x] 如果val在arr出現(xiàn)了兩次,拋出一個(gè)異常

  • [x] 如果val在arr出現(xiàn)了兩次,將arr中的元素都設(shè)置為0,然后拋出一個(gè)異常

  • [x] 如果arr不為空但是val沒有出現(xiàn),選取一個(gè)隨機(jī)的索引,將其對應(yīng)的元素設(shè)置為val ,然后返回這個(gè)索引

  • [x] 如果arr[0]是val ,繼續(xù)檢查剩下的元素,返回索引最高的那個(gè)val對飲的索引(沒有再次找到val就返回0)

Logical implementation

作為find的實(shí)現(xiàn)者,當(dāng)arr為空的時(shí)候,為什么要拋出一個(gè)異常?

  • [ ] DRY(譯者注:Don't repeat yourself)
  • [x] 快速失敗/報(bào)錯
  • [ ] 避免幻數(shù)
  • [ ] 一個(gè)變量只有一個(gè)目的
  • [ ] 避免全局變量
  • [ ] 返回結(jié)果

Java中的規(guī)格說明

有一些語言(例如 Eiffel ),將前置條件和后置條件作為語言的基礎(chǔ)之一,以便程序運(yùn)行的時(shí)候(或者編譯器)可以自動檢查客戶和實(shí)現(xiàn)者是否都遵循了規(guī)格說明。

Java并沒有這么嚴(yán)格,但是它的靜態(tài)檢查也是屬于一種前置條件和后置條件的檢查(編譯器)。至于剩下的部分——那些不屬于數(shù)據(jù)類型范疇的約束——必須通過注釋寫在方法的前面,通過人們來檢查和保證。

Java對于 文檔注釋有一些傳統(tǒng),例如參數(shù)的說明以 @param作為開頭,返回的說明以@return 作為開頭。你應(yīng)該將前置條件放在@param 的地方,后置條件放在 @return的地方。例如,一個(gè)規(guī)格說明可能是這樣:

static int find(int[] arr, int val) - requires:val occurs exactly once in arr - effects:returns index i such that arr[i] = val

… 它在Java中可能被注釋為這樣:

/*** Find a value in an array.* @param arr array to search, requires that val occurs exactly once* in arr* @param val value to search for* @return index i such that arr[i] = val*/ static int find(int[] arr, int val)

Java API 文檔 就是通過Java標(biāo)準(zhǔn)庫源碼中的規(guī)格說明注釋生成的. 同樣的,Eclipse也可以根據(jù)你的規(guī)格說明產(chǎn)生對應(yīng)的文檔),或者產(chǎn)生和Java API一個(gè)格式的 HTML 文檔 ,這對你和你的客戶來說都是很有用的信息。

參考閱讀:

Java: Javadoc Comments

Oracle: How to Write Doc Comments

閱讀小練習(xí)

Javadoc

思考以下規(guī)格說明:

static boolean isPalindrome(String word) - requires:word contains only alphanumeric characters - effects:returns true if and only if word is a palindrome

對應(yīng)的Javadoc注釋:

/** Check if a word is a palindrome.* A palindrome is a sequence of characters* that reads the same forwards and backwards.* @param String word* @requires word contains only alphanumeric characters* @effects returns true if and only if word is a palindrome* @return boolean*/

請問Javadoc中哪一行是有問題的?

  • [x] /*
  • [ ] * Check if a word is a palindrome.
  • [ ] * A palindrome is a sequence of characters
  • [ ] * that reads the same forwards and backwards.
  • [x] * @param String word
  • [x] * @requires word contains only alphanumeric characters
  • [x] * @effects returns true if and only if word is a palindrome
  • [x] * @return boolean
  • [ ] */

Concise Javadoc specs

思考下面這個(gè)規(guī)格說明Javadoc,判斷每一句的作用(逆序):

/*** Calculate the potential energy of a mass in Earth's gravitational field.* @param altitude altitude in meters relative to sea level* @return potential energy in joules*/ static double calculateGravitationalPotentialEnergy(double altitude);

static double calculateGravitationalPotentialEnergy(double altitude);

  • [ ] 前置條件

  • [ ] 后置條件

  • [x] 是前置條件也是后置條件

  • [ ] 都不是

@return potential energy in Joules

  • [ ] 前置條件

  • [x] 后置條件

  • [ ] 是前置條件也是后置條件

  • [ ] 都不是

@param altitude altitude in meters relative to sea level

  • [x] 前置條件

  • [ ] 后置條件

  • [ ] 是前置條件也是后置條件

  • [ ] 都不是

Calculate the potential energy of a mass in Earth's gravitational field.

  • [ ] 前置條件
  • [ ] 后置條件
  • [ ] 是前置條件也是后置條件
  • [x] 都不是

Null 引用

在Java中,對于對象和數(shù)組的引用可以取一個(gè)特殊的值null ,它表示這個(gè)這個(gè)引用還沒有指向任何對象。Null值在Java類型系統(tǒng)中是一個(gè)“不幸的黑洞”。

原始類型不能是null :

int size = null; // illegal double depth = null; // illegal

我們可以給非原始類型的變量賦予null值:

String name = null; int[] points = null;

在編譯期的時(shí)候,這是合法的。但是如果你嘗試調(diào)用這個(gè)null對象的方法或者訪問它里面對應(yīng)的數(shù)值,發(fā)產(chǎn)生一個(gè)運(yùn)行時(shí)錯誤:

name.length() // throws NullPointerException points.length // throws NullPointerException

要注意是,null并不等于“空”,例如一個(gè)空的字符串""或者一個(gè)空的數(shù)組。對于一個(gè)空的字符串或者數(shù)組,你可以調(diào)用它們的方法或者訪問其中的數(shù)據(jù),只不過它們對應(yīng)的元素長度是0罷了(調(diào)用 length() )。而對于一個(gè)指向null的String類型變量——它什么都不是:調(diào)用 length() 會產(chǎn)生一個(gè)NullPointer-Exception.

另外要注意一點(diǎn),非原始類型的聚合類型例如List可能不指向null但是它的元素可能指向null :

String[] names = new String[] { null }; List<Double> sizes = new ArrayList<>(); sizes.add(null);

如果有人嘗試使用這些為null的元素,報(bào)錯依然會發(fā)生。

使用Null值很容易發(fā)生錯誤,同時(shí)它們也是不安全的,所以在設(shè)計(jì)程序的時(shí)候盡可能避開它們。在這門課程中——事實(shí)上在大多數(shù)好的Java編程中——一個(gè)約定俗成規(guī)矩就是參數(shù)和返回值不是null。 所以每一個(gè)方法都隱式的規(guī)定了前置條件中數(shù)組或者其他對象不能是null,同時(shí)后置條件中的返回對象也不會是null值(除非規(guī)格說明顯式的說明了可能返回null,不過這通常不是一個(gè)好的設(shè)計(jì))。總之,避免使用null!

在Java中你可以在類型中顯式的禁用null , 這樣會在編譯期和運(yùn)行時(shí)自動檢查null值:

static boolean addAll(@NonNull List<T> list1, @NonNull List<T> list2)

Google 也對null的使用進(jìn)行了一些討論,其中說到:

不嚴(yán)謹(jǐn)?shù)氖褂胣ull可以導(dǎo)致各種各樣的bug。通過統(tǒng)計(jì)Google的代碼庫,我們發(fā)現(xiàn)有95%的聚合類型不應(yīng)該有任何null值,如果利用這個(gè)性質(zhì)快速失敗的話比默默接受這些null值更能幫助開發(fā)。

另外,null值是有歧義的。通常很難判斷一個(gè)null的返回值意味著什么——例如, Map.get(key) 可能在key對應(yīng)的value是null的時(shí)候返回null,也可能是因?yàn)関alue不存在而返回null。null可以意味著失敗,也可以意味著成功,它可以是任何東西。使用非null的值能夠使得你的代碼更加清晰易懂。

譯者注:"這是我犯的一個(gè)巨大錯誤" - Sir C. A. R. Hoare, null引用的發(fā)明者

閱讀小練習(xí)

NullPointerException accessing exercise.name()

下面哪些變量可以是null ?

  • [ ] int a;

  • [ ] char b;

  • [ ] double c;

  • [x] int[] d;

  • [x] String e;

  • [x] String[] f;

  • [ ] Double g;

  • [x] List<Integer> h;

  • [x] final MouseTrap i;

  • [x] static final String j;

There are null exercises remaining

public static String none() {return null; // (1) }public static void main(String[] args) {String a = none(); // (2)String b = null; // (3)if (a.length() > 0) { // (4)b = a; // (5)}return b; // (6) }

哪一行有靜態(tài)錯誤? -> 6

如果們將上一個(gè)問題的行注釋掉,然后運(yùn)行 main…

哪一行會有運(yùn)行時(shí)錯誤? -> 4

規(guī)格說明應(yīng)該說些什么

一個(gè)規(guī)格說明應(yīng)該談到接口的參數(shù)和返回的值,但是它不應(yīng)該談到局部變量或者私有的(private)內(nèi)部方法或數(shù)據(jù)。這些內(nèi)部的實(shí)現(xiàn)應(yīng)該在規(guī)格說明中對讀者隱藏。

在Java中,規(guī)格說明的讀者通常不會接觸到實(shí)現(xiàn)的源碼,應(yīng)為Javadoc工具通過你的源碼自動生成對應(yīng)的規(guī)格說明并渲染成HTML。


測試與規(guī)格說明

在測試中,我們談到了黑盒測試意味著僅僅通過規(guī)格說明構(gòu)建測試,而白盒測試是通過代碼實(shí)現(xiàn)來構(gòu)建測試(譯者注:閱讀03“測試”)。但是要特別注意一點(diǎn):即使是白盒測試也必須遵循規(guī)格說明。 你的實(shí)現(xiàn)也許很依賴前置條件的滿足,否則方法就會有一個(gè)未定義的行為。而你的測試是不能依賴這種未定義的行為的。測試用例必須尊徐規(guī)格說明,就像每一個(gè)客戶一樣。

例如,假設(shè)你正在測試find,它的規(guī)格說明如下:

static int find(int[] arr, int val) - requires:val occurs in arr - effects:returns index i such that arr[i] = val

這個(gè)規(guī)格說明已經(jīng)很明顯的要求了前置條件——val必須在arr中存在,而且它的后置條件很“弱”——沒有規(guī)定返回哪一個(gè)索引,如果在arr中有多個(gè)val的話。甚至如果你的實(shí)現(xiàn)就是總是返回最后一個(gè)索引,你的測試用例也不能依賴這種行為。

int[] array = new int[] { 7, 7, 7 }; assertEquals(0, find(array, 7)); // bad test case: violates the spec assertEquals(7, array[find(array, 7)]); // correct

類似的,即使你實(shí)現(xiàn)的find會在找不到val的時(shí)候拋出一個(gè)異常,你的測試用例也不能依賴這種行為,因?yàn)樗荒茉谶`背前置條件的情況下調(diào)用find() 。

那么白盒測試意味著什么呢?如果它不能違背規(guī)格說明的話?它意味著你可以通過代碼的實(shí)現(xiàn)去構(gòu)建不同的測試用例,以此來測試不同的實(shí)現(xiàn),但是依然要檢查這些測試用例符合規(guī)格說明。

測試單元

回想在閱讀03“測試” 中的web search例子:

/** @return the contents of the web page downloaded from url */ public static String getWebPage(URL url) { ... }/** @return the words in string s, in the order they appear,* where a word is a contiguous sequence of* non-whitespace and non-punctuation characters */ public static List<String> extractWords(String s) { ... }/** @return an index mapping a word to the set of URLs* containing that word, for all webpages in the input set */ public static Map<String, Set<URL>> makeIndex(Set<URL> urls) { ...calls getWebPage and extractWords... }

一個(gè)好的單元測試應(yīng)該僅僅關(guān)注于一個(gè)規(guī)格說明。我們的測試不應(yīng)該依賴于另一個(gè)要測試的單元。例如上面例子中,當(dāng)我們在對 extractWords 測試時(shí),就不應(yīng)該使用getWebPage 的輸出作為輸入,因?yàn)槿绻鹓etWebPage 發(fā)生了錯誤, extractWords 的行為很可能是未定義的。

而對于一個(gè)好的綜合測試(測試多個(gè)模塊),它確保的是各個(gè)模塊之間是兼容的:調(diào)用者和被調(diào)用者之間的數(shù)據(jù)輸入輸出應(yīng)該是符合要求的。同時(shí)綜合測試不能取代系統(tǒng)的單元測試,因?yàn)楦鱾€(gè)模塊的輸出集合很可能在輸入空間中沒有代表性。例如我們只通過調(diào)用 makeIndex測試extractWords .而extractWords的輸出又不能覆蓋掉 makeIndex的很多輸入空間,這樣我們以后在別處復(fù)用 makeIndex的時(shí)候,就很可能產(chǎn)生意想不到的錯誤。


改變對象方法的規(guī)格說明

我們在之前的閱讀材料中談到了可改變的對象 vs. 不可改變的對象。但是我們對于find的規(guī)格說明(后置條件)并沒有告訴我們這個(gè)副作用——對象的內(nèi)容被改變了。

以下是一個(gè)告訴了這種作用的規(guī)格說明,它來自Java中 List接口:

static boolean addAll(List<T> list1, List<T> list2) - requires:list1 != list2 - effects:modifies list1 by adding the elements of list2 to the end of it, and returns true if list1 changed as a result of call

首先看看后置條件,它給出了兩個(gè)限制:list1會被更改;返回值是怎么確定的。

再來看看前置條件,我們可以發(fā)現(xiàn),如果我們試著將一個(gè)列表加到它本身,其結(jié)果是未定義的(即規(guī)格說明未指出)。這也很好理解,這樣的限制可以使得實(shí)現(xiàn)更容易,例如我們可以將第二個(gè)列表的元素逐個(gè)加入到第一個(gè)列表中。如果嘗試將兩個(gè)指向同一個(gè)對象的列表相加,就可能發(fā)生下圖的情況,即將列表2的元素添加到列表1中后同時(shí)也改變了列表2,這樣方法可能不會終止(或者最終內(nèi)存不夠而拋出異常):

另外,上文“Null 引用”提到過,這還有一個(gè)隱含的前置條件:list1和list2都不是null ,。

這里有另一個(gè)改變對象方法的例子:

static void sort(List<String> lst) - requires:nothing - effects:puts lst in sorted order, i.e. lst[i] ≤ lst[j] for all 0 ≤ i < j < lst.size()

和一個(gè)不改變對象方法的例子:

static List<String> toLowerCase(List<String> lst) - requires:nothing - effects:returns a new list t where t[i] = lst[i].toLowerCase()

正如null是隱式的不被允許的,我們也隱式的規(guī)定改變對象(mutation)是不被允許的,除非顯式的聲明 。例如 to-Lower-Case 的規(guī)格說明中就沒有談到該方法會不會改變參數(shù)對象(不會改變),而sort中就顯式的說明了。

READING EXERCISES閱讀小練習(xí)

What’s in a spec?

下面哪一些選項(xiàng)是屬于規(guī)格說明的?

  • [x] 返回類型

  • [x] 返回值的范圍

  • [x] 參數(shù)個(gè)數(shù)

  • [x] 參數(shù)種類

  • [x] 對參數(shù)的限制

gcd 1

Alice 寫了如下代碼:

public static int gcd(int a, int b) {if (a > b) {return gcd(a-b, b);} else if (b > a) {return gcd(a, b-a);}return a; }

Bob 寫了如下對應(yīng)測試:

@Test public void gcdTest() {assertEquals(6, gcd(24, 54)); }

測試通過了!以下哪些說法是正確的?

Alice 應(yīng)該在前置條件中加上 a > 0 -> True

Alice 應(yīng)該在前置條件中加上 b > 0 -> True

Alice 應(yīng)該在后置條件中加上 gcd(a, b) > 0 -> False

Alice 應(yīng)該在后置條件中加上 a and b are integers -> False

gcd 2

如果Alice 在前置條件中加上 a > 0 , Bob 應(yīng)該測試負(fù)數(shù) a -> False

如果Alice 沒有在前置條件中加上 a > 0 , Bob 應(yīng)該測試負(fù)數(shù) a -> True


異常

現(xiàn)在我們來討論一下如何處理異常的情況,并且這種處理既能遠(yuǎn)離bug又能易于理解。

一個(gè)方法的標(biāo)識(signature)包含它的名字、參數(shù)類型、返回類型,同時(shí)也包含該方法能觸發(fā)的異常。

參考閱讀: Exceptions in the Java Tutorials.

報(bào)告bug的異常

你可能已經(jīng)在Java編程中遇到了一些異常,例如 ArrayIndex-OutOfBounds-Exception (數(shù)組訪問越界)或者 Null-Pointer-Exception (訪問一個(gè)null引用的對象)。這些異常通常都是用來報(bào)告你代碼里的bug ,同時(shí)它們報(bào)告的信息也能幫助你修復(fù)bug。

ArrayIndex-OutOfBounds- 和 Null-Pointer-Exception 大概是最常見的異常了,其他的例子有:

  • ArithmeticException, 當(dāng)發(fā)生計(jì)算錯誤時(shí)拋出,例如除0。
  • NumberFormatException, 數(shù)字的類型不匹配的時(shí)候拋出,例如你向Integer.parseInt 傳入一個(gè)字符長而不是一個(gè)整數(shù)。

報(bào)告特殊結(jié)果的異常

異常不僅被用來報(bào)告bug,它們也被用來提升那些包含特殊結(jié)果的代碼的結(jié)構(gòu)。

不幸的是,一個(gè)常見的處理特殊結(jié)果的方法就是返回一個(gè)特殊的值。你在Java庫中常常能發(fā)現(xiàn)這樣的設(shè)計(jì):當(dāng)你期望一個(gè)正整數(shù)的時(shí)候,特殊結(jié)果會返回一個(gè)-1;當(dāng)你期望一個(gè)對象的時(shí)候,特殊結(jié)果會返回一個(gè)null 。這樣的方法如果謹(jǐn)慎使用也還OK,但是它有兩個(gè)問題。首先,它加重的檢查返回值的負(fù)擔(dān)。其次,程序員很可能會忘記檢查返回值(我們待會會看到通過使用異常,編譯器會幫助你處理這些問題)。

同時(shí),找到一個(gè)“特殊值”返回并不是一件容易的事?,F(xiàn)在假設(shè)我們有一個(gè) BirthdayBook 類,其中有一個(gè)lookup方法:

class BirthdayBook {LocalDate lookup(String name) { ... } }

(LocalDate 是Java API的一個(gè)類.)

如果name在這個(gè)BirthdayBook中沒有入口,這個(gè)方法該如何返回呢?或許我們可以找一個(gè)永遠(yuǎn)不會被人用到的日期。糟糕的程序員或許會選擇一個(gè)9/9/99,畢竟他們覺得沒有人會在這個(gè)世紀(jì)結(jié)束的時(shí)候使用這個(gè)程序。((事實(shí)上,它們錯了)

這里有一個(gè)更好的辦法,就是拋出一個(gè)異常:

LocalDate lookup(String name) throws NotFoundException {...if ( ...not found... )throw new NotFoundException();...

調(diào)用者使用catch捕獲這個(gè)異常:

BirthdayBook birthdays = ... try {LocalDate birthdate = birthdays.lookup("Alyssa");// we know Alyssa's birthday } catch (NotFoundException nfe) {// her birthday was not in the birthday book }

現(xiàn)在我們就不需要使用“特殊”的返回值來通報(bào)特殊情況了,調(diào)用者也不需要再檢查返回值。

閱讀小練習(xí)

1st birthday

假設(shè)我們在使用 BirthdayBook 中的 lookup 方法,它可能會拋出 NotFoundException.

如果“Elliot”不在birthdays里面(birthdays已經(jīng)初始化了,并指向了一個(gè)對象),下面這些代碼會發(fā)生什么?

try {LocalDate birthdate = birthdays.lookup("Elliot"); }

運(yùn)行時(shí)報(bào)錯: NotFoundException

2nd birthday

try {LocalDate birthdate = birthdays.lookup("Elliot"); } catch (NotFoundException nfe) {birthdate = LocalDate.now(); }

靜態(tài)錯誤: undeclared variable

3rd birthday

try {LocalDate birthdate = birthdays.lookup("Elliot"); } catch (NotFoundException nfe) {throw new DateTimeException("Missing reference birthday", nfe); }

(DateTimeException is provided by the Java API.)

運(yùn)行時(shí)報(bào)錯: DateTimeException


已檢查(Checked)異常和未檢查(Unchecked)異常

我們已經(jīng)看到了兩種不同目的的異常:報(bào)告特殊的結(jié)果或者報(bào)告bug。一個(gè)通用的規(guī)則是,我們用已檢查的異常來報(bào)告特殊結(jié)果,用未檢查的異常來報(bào)告bug。在后面一節(jié)中,我們會詳細(xì)介紹一些。

“ 已檢查 異常”這個(gè)名字是因?yàn)榫幾g器會檢查這種異常是否被正確處理:

  • 如果一個(gè)方法拋出一個(gè)已檢查異常,這種可能性必須添加到它的標(biāo)識中。例如 Not-Found-Exception就是一個(gè)已檢查異常,這也是為什么它的生命的結(jié)尾有一個(gè) throws Not-Found-Exception.
  • 如果一個(gè)方法調(diào)用一個(gè)可能拋出已檢查異常的方法,該方法要么處理它,要么在它的標(biāo)識中說明該異常(交給它的調(diào)用者處理)。

所以如果你調(diào)用了 BirthdayBook中的 lookup 并忘記處理 Not-Found-Exception ,編譯器就會拒絕你的代碼。這非常有用,因?yàn)樗_保了那些可能產(chǎn)生的特殊情況(異常)被處理。

相應(yīng)的,未檢查異常用來報(bào)告bug。這些異常并不指望被代碼處理(除了一些頂層的代碼),同時(shí)這樣的異常也不應(yīng)該被顯式拋出,例如邊界溢出、null值、非法參數(shù)、斷言失敗等等。同樣,編譯器不會檢查這些異常是否被 try-catch 處理或者用 throws 拋給上一層調(diào)用者。(Java允許你將未檢查的異常作為方法的標(biāo)識,不過這沒有什么意義,我們也不建議這么做)

異常中有可能有和異常相關(guān)的信息。(如果構(gòu)建體沒有提供,引用這個(gè)信息(String)的值將會是null )

Throwable 類層次

為了理解Java是如何定義一個(gè)異常是已檢查還是未檢查的,讓我們看一看Java異常類的層次圖:

Throwable 是一個(gè)能夠被拋出和捕獲的對象對應(yīng)的類。Throwable的實(shí)現(xiàn)記錄了棧的結(jié)構(gòu)(異常被拋出的時(shí)候),同時(shí)還有一個(gè)描述該異常的消息(可選)。任何被拋出或者捕獲的異常對象都應(yīng)該是 Throwable的子類。

Error 是 Throwable 的一個(gè)子類,它被保留用于Java運(yùn)行系統(tǒng)的異常,例如 StackOverflow-Error 和 OutOfMemory-Error.Errors應(yīng)該被認(rèn)為是不可恢復(fù)的,并且一般不會去捕獲它。(這里有一個(gè)特例, Assertion-Error 也是屬于Error 的,即使它反映的是用戶代碼錯誤)

下面描述了在Java中如何區(qū)別已檢查異常和未檢查異常:

  • RuntimeException, Error, 以及它們的子類都是未檢查異常。編譯器不會要求它們被throws修飾,也不會要求它們被捕獲。
  • 所有其他的throwables—— Throwable, Exception和其他子類都是已檢查異常。編譯器會要求它們被捕獲或者用throws傳給調(diào)用者處理。

當(dāng)你定義你自己的異常時(shí),你應(yīng)該使它要么是 RuntimeException 的子類(未檢查異常),要么是 Exception 的子類(已檢查異常)。程序員通常不會生成 Error 或者 Throwable的子類,因?yàn)樗鼈兺ǔ1籎ava保留使用。

閱讀小練習(xí)

Get to the point

假設(shè)我們寫了一個(gè)尋找兩點(diǎn)之間路徑的方法:

public static List<Point> findPath(Point initial, Point goal)

In the postcondition, we say that findPath will search for paths only up to a bounded length (set elsewhere), and that it will throw an exception if it fails to find one.在前置條件中,我們要求findPath 搜索的范圍是有限的(有邊界)。如果該方法沒有找到一個(gè)路徑,它就會拋出一個(gè)異常。

在設(shè)計(jì)方法時(shí),以下哪一個(gè)異常是合理的?

  • [ ] 已檢查異常 NoPathException
  • [ ] 未檢查異常 NoPathException
  • [x] 已檢查異常 PathNotFoundException
  • [ ] 未檢查異常 PathNotFoundException

Don’t point that thing at me

當(dāng)我們定義該異常時(shí),應(yīng)該使它是哪一個(gè)類的子類?

  • [ ] Throwable
  • [x] Exception
  • [ ] Error
  • [ ] RuntimeException


設(shè)計(jì)異常時(shí)應(yīng)該考慮的事情

我們之前給了一個(gè)通用規(guī)則——對于特殊的結(jié)果(預(yù)測到的)使用已檢查異常,對于bug使用未檢查異常(意料之外)。這說得通,不過,在Java中異常并沒有這么“輕量化”。

除了對性能有影響,Java中的異常會帶來使用上的開銷:如果你要設(shè)計(jì)一個(gè)異常,你必須創(chuàng)建一個(gè)新的類。如果你調(diào)用一個(gè)可能拋出已檢查異常的方法,你必須使用 try-catch 處理它(即使你知道這個(gè)異常一定不會發(fā)生)。后一種情況導(dǎo)致了一個(gè)進(jìn)退兩難的局面。例如,你設(shè)計(jì)了一個(gè)抽象隊(duì)列,你是應(yīng)該期望使用者在循環(huán)pop的時(shí)候檢查隊(duì)列是否為空(作為前置條件),還是讓使用者自由的pop,最后拋出一個(gè)異常呢?如果你選擇拋出異常,那么即使使用者每次都檢查隊(duì)列不為空才pop,他還是要對這個(gè)異常進(jìn)行處理。

所以我們提煉出另一個(gè)明確的規(guī)則:

  • 對于意料之外的bug使用未檢查的異常,或者對于使用者來說避免異常產(chǎn)生的情況非常容易(例如檢查一個(gè)隊(duì)列是否為空)。
  • 其他的情況我們使用已檢查異常。

這里舉出一些例子:

  • 當(dāng)隊(duì)列是空時(shí),Queue.pop() 會拋出一個(gè)未檢查異常。因?yàn)闄z查隊(duì)列是否為空對于用戶來說是容易的。(例如 Queue.size() or Queue.isEmpty().)
  • 當(dāng)無法連接互聯(lián)網(wǎng)時(shí),Url.getWebPage() 拋出一個(gè)已檢查異常 IOException ,因?yàn)榭蛻艨赡軣o法確定調(diào)用的時(shí)候網(wǎng)絡(luò)是否好使。
  • 當(dāng)x沒有整數(shù)開方時(shí),int integerSquareRoot(int x) 拋出一個(gè)已檢查異常 Not-Perfect-Square-Exception ,因?yàn)閷τ谡{(diào)用者來說,判斷一個(gè)整數(shù)是否為平方是困難的。

這些使用異常的“痛楚”也是很多Java API使用null引用或特殊值作為返回值的原因。額.....如果你嚴(yán)謹(jǐn)認(rèn)真的使用這些返回值,這也不是什么糟糕的事情。

在規(guī)格說明中應(yīng)該如何聲明異常

因?yàn)楫惓R部梢詺w為方法的輸出,所以我們應(yīng)該在規(guī)格說明的后置條件中描述它。Java中是以 @throws 作為Javadoc中異常注釋的。Java也可能要求函數(shù)聲明時(shí)用throws標(biāo)出可能拋出的異常 。這一節(jié)會討論什么時(shí)候使用這兩種方法。

對于非檢查的異常,由于它們描述的是意料之外的bug或者失敗,不屬于后置條件,所以不應(yīng)該用 @throws 或 throws修飾它們。例如, NullPointerException就不應(yīng)該在規(guī)格說明中列出——我們的前置條件已經(jīng)隱式(顯式)的禁止了null值,這意味著如果使用者傳入一個(gè)null,我們可以沒有任何警告的扔出一個(gè)異常。例如下面這個(gè)規(guī)格說明,就沒有提到 NullPointerException :

/*** @param lst list of strings to convert to lower case* @return new list lst' where lst'[i] is lst[i] converted to lowercase*/ static List<String> toLowerCase(List<String> lst)

而對于報(bào)告特殊結(jié)果的異常,我們應(yīng)該在Javadoc中用 @throws 表示出來,并明確什么情況下會導(dǎo)致這個(gè)異常的拋出。另外,如果是一個(gè)已檢查異常,Java會要求在函數(shù)聲明的時(shí)候用 throws 標(biāo)識出來。例如,假設(shè) NotPerfectSquareException 是一個(gè)已檢查聲明:

/*** Compute the integer square root.* @param x value to take square root of* @return square root of x* @throws NotPerfectSquareException if x is not a perfect square*/ int integerSquareRoot(int x) throws NotPerfectSquareException;

對于報(bào)告特殊結(jié)果的未檢查異常,Java允許但是不要求使用 throws 在聲明中標(biāo)識出。但是這種情況下通常不要使用 throws 因?yàn)檫@會使得閱讀者困惑(以為它是一個(gè)已檢查異常)。例如,假設(shè)你將EmptyQueueException定義為未檢查異常。那么你應(yīng)該在Javadoc中使用 @throws對其進(jìn)行說明,但是不要在函數(shù)聲明中將其標(biāo)識出:

/*** Pops a value from this queue.* @return next value in the queue, and removes the value from the queue* @throws EmptyQueueException if this queue is empty*/ int pop();

閱讀小練習(xí)

Throw all the things!

閱讀以下代碼并分析 Thing 對象:

static Set<Thing> ALL_THE_THINGS;static void analyzeEverything() {analyzeThingsInOrder(); }static void analyzeThingsInOrder() {try {for (Thing t : ALL_THE_THINGS) {analyzeOneThing(t);}} catch (AnalysisException ae) {return;} }static void analyzeOneThing(Thing t) throws AnalysisException {// ...// ... maybe go off the end of an array// ... }

AnalysisException 是一個(gè) 已檢查 異常.

analyzeEverything可能會拋出哪一些異常?

  • [x] ArrayIndexOutOfBoundsException

  • [ ] IOException

  • [x] NullPointerException

  • [ ] AnalysisException

  • [ ] OutOfMemoryError

A terrible thing

如果 analyzeOneThing 自己會拋出一個(gè) AnalysisException 異常,會發(fā)生什么?

  • [ ] 程序可能會崩潰

  • [x] 我們可能不能調(diào)用任何 analyzeOneThing

  • [ ] 我們可能會調(diào)用幾次 analyzeOneThing


總結(jié)

最后,再做一組練習(xí)看看你對今天學(xué)的內(nèi)容理解的如何。

閱讀小練習(xí)

拼字游戲 1

/* Requires: tiles has length 7 & contains only uppercase letters.crossings contains only uppercase letters, without duplicates.Effects: Returns a list of words where each word can be made by takingletters from tiles and at most 1 letter from crossings.*/ public static List<String> scrabble(String tiles, String crossings) {if (tiles.length() != 7) { throw new RuntimeException(); }return new ArrayList<>(); }

scrabble的后置條件有哪些?

  • [ ] tiles 中只有大寫字母
  • [ ] crossings 中字母沒有重復(fù)
  • [ ] scrabble 需要兩個(gè)參數(shù)
  • [x] scrabble 返回字符串列表

scrabble的前置條件有哪些?

  • [x] tiles 長度為 7
  • [x] crossings 是一個(gè)大寫的字符串
  • [x] scrabble參數(shù)的類型是 String 和 String
  • [ ] scrabble 返回一個(gè)空的 ArrayList

拼字游戲 2

規(guī)格說明中的哪一部分是會被靜態(tài)檢查的?

  • [ ] tiles 中只有大寫字母
  • [ ] crossings 中字母沒有重復(fù)
  • [ ] 當(dāng) tiles.length() != 7, scrabble 拋出 RuntimeException
  • [x] scrabble 接收兩個(gè)參數(shù)

scrabble 的實(shí)現(xiàn)滿足了規(guī)格說明嗎?

  • [ ] 是
  • [ ] 否, 因?yàn)樗鼤跓o法獲取tiles長度時(shí)拋出 RuntimeException
  • [x] 否,因?yàn)榧词刮覀儌魅胍粋€(gè)可以組合成詞的tiles和crossings,它也會返回一個(gè)空列表。

一個(gè)規(guī)格說明就好像是實(shí)現(xiàn)者和使用者之間的防火墻。它使得分別開發(fā)成為可能:使用者可以在不理解源代碼的情況下使用模塊,實(shí)現(xiàn)者可以在不知道模塊如何被使用的情況下實(shí)現(xiàn)模塊。

現(xiàn)在讓我們想想今天的內(nèi)容和我們?nèi)竽繕?biāo)之間的聯(lián)系:

  • 遠(yuǎn)離bug. 一個(gè)好的規(guī)格說明會清晰明確的要求實(shí)現(xiàn)者和使用者遵守相關(guān)的制約。而Bug經(jīng)常是因?yàn)閷?shí)現(xiàn)者和使用者對于接口的理解沖突導(dǎo)致的,規(guī)格說明會明顯的減小這種可能性。在模塊中使用一些能夠交由機(jī)器檢查的特性,例如靜態(tài)檢查、異常等而不是注釋會進(jìn)一步降低bug的可能性。
  • 易讀性. 一個(gè)簡潔準(zhǔn)確的規(guī)格說明會比源代碼本身更易讀易懂。
  • 可改動性. 規(guī)格說明在實(shí)現(xiàn)者和使用者之間建立了一個(gè)“契約”——只要這兩方遵守這份“契約”,他們可以對自己的代碼進(jìn)行任何改變。

轉(zhuǎn)載于:https://www.cnblogs.com/liqiuhao/p/8566500.html

總結(jié)

以上是生活随笔為你收集整理的麻省理工18年春软件构造课程阅读06“规格说明”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

亚洲精品一区二区三区在线观看 | 在线观看中文字幕2021 | 中文字幕 国产视频 | 在线小视频你懂的 | 国产精品成人一区二区 | 一级黄色毛片 | 欧美视频日韩 | 色www精品视频在线观看 | 欧美一二三区在线观看 | www.久久久 | 香蕉视频网站在线观看 | 五月婷婷丁香六月 | 黄色软件在线观看免费 | 97在线观| 日女人免费视频 | 久久久久久国产一区二区三区 | 99久久久成人国产精品 | 日韩免费视频 | 超碰人人在线 | 精品在线不卡 | 国产 在线 日韩 | 国产免费二区 | 久久成年人视频 | 九九久久精品 | 四虎在线免费观看 | 色偷偷av男人天堂 | 亚洲涩涩涩涩涩涩 | 亚洲 欧美变态 另类 综合 | 丁香花在线视频观看免费 | 手机看片1042 | 丁香五香天综合情 | 久久久成人精品 | 高清视频一区二区三区 | 亚洲黄色免费 | 黄色免费网站下载 | 日韩在线观看网址 | 日产乱码一二三区别在线 | 久草.com| 亚洲精品乱码久久久久久高潮 | 三级a视频| 国产 欧美 日韩 | 国产精品久久久久久久久久新婚 | 国产一区二区不卡在线 | 在线观看午夜 | 中文字幕亚洲高清 | 黄色av一级 | 国产伦理久久 | 久久国产精品偷 | 日本在线中文在线 | www.在线看片.com | 奇米四色影狠狠爱7777 | 国产一级在线观看视频 | 国产精品免费视频一区二区 | 天天综合网天天 | 操高跟美女 | 日韩欧美一级二级 | 黄色在线观看网站 | 青青啪 | 日韩黄色一区 | 成人看片 | 日韩欧美高清 | 日本性动态图 | 久久久久福利视频 | 69av视频在线观看 | 波多野结衣理论片 | 亚洲人天堂 | 久久热首页 | 国产专区一 | 国产九九九九九 | 五月婷婷播播 | 天天综合91 | a电影免费看 | 成人黄色短片 | 1024久久 | 国产一区成人在线 | 亚洲国产中文字幕在线视频综合 | 日本激情中文字幕 | 久久99国产精品免费网站 | 亚洲高清视频一区二区三区 | 久久视频网址 | 国产亚洲精品久 | 精品国自产在线观看 | 91精品在线播放 | 国产无遮挡猛进猛出免费软件 | 日韩丝袜 | 亚洲人成人99网站 | 最近日本中文字幕a | 国产精品每日更新 | 97电影在线看视频 | 成人毛片100免费观看 | 久久草视频 | 在线午夜电影神马影院 | www.色午夜.com | 有码视频在线观看 | 日本黄色免费在线观看 | 婷婷丁香激情综合 | 亚洲欧美视频 | 国产网红在线 | 四虎免费在线观看 | av久久久 | 激情欧美国产 | 日韩毛片在线免费观看 | 色爽网站 | 三级av黄色 | 日韩视频一区二区三区在线播放免费观看 | 成人久久18免费网站图片 | 亚洲精品视频第一页 | 啪啪免费观看网站 | 狠狠网亚洲精品 | 欧美日韩超碰 | 草草草影院 | 97成人免费 | 亚洲精品动漫久久久久 | 在线观看免费中文字幕 | 亚洲人久久久 | 伊人成人激情 | 99久国产 | 天天操夜夜操 | 日本色小说视频 | 草久久影院 | 丁香导航 | 日韩av区| 免费毛片一区二区三区久久久 | av千婊在线免费观看 | 色婷婷88av视频一二三区 | 日本性视频 | 国产自在线 | 免费观看mv大片高清 | 国产精品第二十页 | 青青草在久久免费久久免费 | 成人黄大片 | 日韩伦理一区二区三区av在线 | 在线电影日韩 | 成 人 a v天堂| 亚洲综合黄色 | 亚洲日韩中文字幕 | 国产免费国产 | 99精品视频播放 | 久久久久亚洲精品 | 国产精品18久久久久久久久久久久 | 在线观看免费福利 | 国产特级毛片aaaaaaa高清 | 日日爱av | 天天操天天玩 | 亚洲午夜精 | 国产精品黄色 | 日本天天色 | 日本久久久久久久久 | 久久精品爱爱视频 | 天堂va欧美va亚洲va老司机 | 免费日韩一区二区 | 天堂在线一区二区三区 | 热re99久久精品国产66热 | 国产高清无av久久 | www.国产毛片 | 久草| 天天射色综合 | 91久久电影 | 一区二区三区四区不卡 | 91精品国产网站 | 免费av电影网站 | 中文字幕资源在线观看 | 国产成人精品一二三区 | 久久久精品一区二区 | 超碰97免费| 色噜噜色噜噜 | 女人18毛片90分钟 | 欧美日韩视频在线观看一区二区 | 91麻豆文化传媒在线观看 | 欧美久久久久久久久中文字幕 | 在线久草视频 | 国产视频不卡一区 | 91av在线不卡 | 亚洲永久精品在线观看 | 视频一区二区免费 | 亚洲成a人片综合在线 | 久久视频在线免费观看 | 日韩69av| 麻豆国产在线视频 | 超碰97人人在线 | 欧美精品亚洲精品 | 婷婷九月丁香 | 久久伊人综合 | 欧美日韩一区二区免费在线观看 | 在线日本看片免费人成视久网 | 国产在线观看免费av | 婷婷色综合色 | 99人成在线观看视频 | 久99久精品视频免费观看 | 欧美日韩精品在线视频 | 日本精品一 | 色噜噜狠狠狠狠色综合 | 欧美日韩一区二区久久 | 99热这里只有精品在线观看 | 中文字幕视频网站 | 久久免费在线视频 | 久久人人97超碰国产公开结果 | 日韩视频a| 中文字幕网址 | 中文字幕视频 | 91精品一区二区三区久久久久久 | 亚洲黄色片 | 一区二区三区影院 | 中文字幕精品一区二区精品 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 久久五月婷婷丁香 | 国内精品久久久久久 | 精品人人人 | 精品国产自在精品国产精野外直播 | 最近更新好看的中文字幕 | 欧美精品亚州精品 | 亚洲成人二区 | 中文字幕av有码 | 特级xxxxx欧美| 一区二区三区高清在线 | 国产成人av | av三级av | 免费网址你懂的 | 中文在线中文a | av在线一级 | 91亚瑟视频 | 五月天久久婷 | 国产精品国内免费一区二区三区 | 欧美日产在线观看 | 免费视频91| 久久久亚洲麻豆日韩精品一区三区 | 美女网站在线播放 | 中文字幕一区二区三区四区久久 | 在线看v片成人 | 国产成人免费精品 | a黄色片在线观看 | 91尤物国产尤物福利在线播放 | 人人爽网站 | 亚洲视频在线观看免费 | 97在线视频免费播放 | 91人人插| 在线之家免费在线观看电影 | 国产午夜精品一区二区三区在线观看 | 香蕉一区 | 91精品对白一区国产伦 | 国产一卡久久电影永久 | 久久久久免费精品国产 | 久久99偷拍视频 | 精品免费国产一区二区三区四区 | 国产精彩视频一区二区 | 69亚洲视频 | 久久久久久国产精品久久 | 国产精品第十页 | 奇米网8888| 欧美久久久久久久久久久久 | 操操操综合| 国产精品 欧美 日韩 | 日韩av快播电影网 | 欧美性久久久 | 毛片网站在线看 | 欧美日韩免费观看一区二区三区 | 麻豆国产精品视频 | 亚洲国产精品成人va在线观看 | 国产无限资源在线观看 | 手机av电影在线 | 免费精品国产va自在自线 | 青春草视频在线播放 | 中文字幕在线字幕中文 | 国产小视频国产精品 | 五月天婷亚洲天综合网鲁鲁鲁 | 黄网站色欧美视频 | 午夜视频在线网站 | 中文有码在线 | 日韩一二三在线 | 久草热久草视频 | 怡红院成人在线 | zzijzzij日本成熟少妇 | 久久综合五月天婷婷伊人 | 国产精品一区二区免费视频 | 色在线国产 | 丁香六月婷婷激情 | av一本久道久久波多野结衣 | 天天操导航 | 伊人热 | 五月婷婷操 | 国产理论一区二区三区 | 91新人在线观看 | 亚洲春色综合另类校园电影 | 伊人电影在线观看 | 99热这里有精品 | 在线电影日韩 | 五月激情视频 | 久久久久久久久久久久亚洲 | 色网站免费在线看 | 免费91麻豆精品国产自产在线观看 | 欧美性大战久久久久 | 日韩三级视频在线观看 | 国产成人精品一区二区三区福利 | 欧美精品天堂 | 天天综合网在线观看 | 黄色av大片 | 免费看黄在线网站 | 免费电影一区二区三区 | 综合天天色 | 久久开心激情 | 国产 日韩 欧美 中文 在线播放 | 国产丝袜一区二区三区 | 欧美中文字幕第一页 | 五月天综合激情网 | 色黄视频免费观看 | 日韩精品短视频 | 亚洲成人欧美 | 在线观看免费91 | 成年人在线播放视频 | 91高清在线看 | 伊人午夜视频 | 婷婷色5月 | av短片在线 | 久久久久久视频 | 国产激情久久久 | 成人小视频在线免费观看 | av三级在线免费观看 | 在线国产高清 | 婷婷丁香五 | 欧美成人免费在线 | 青青色影院 | 在线观看福利网站 | 伊人国产在线观看 | 欧美日韩一区二区在线观看 | 91精品在线免费视频 | 91网在线观看 | 久久久久久久久久久综合 | 久章草在线观看 | 黄色片免费看 | 91精品在线观看视频 | 激情综合网色播五月 | 国产99久久久国产精品免费看 | 国内综合精品午夜久久资源 | 久久精品8| 人人爽人人爽av | 久久夜色精品国产欧美乱 | 亚洲一区二区三区在线看 | www黄色| 玖玖精品在线 | 激情久久伊人 | 国产91精品一区二区麻豆亚洲 | 国产午夜三级一区二区三桃花影视 | 日韩久久精品一区二区三区下载 | 91欧美国产| 97av在线视频免费播放 | 日韩精品久久中文字幕 | 超碰免费av | 日韩成人免费观看 | 成人午夜在线电影 | 国产中的精品av小宝探花 | 亚洲黄色免费在线看 | 免费看特级毛片 | 美女黄濒 | 国产一级一片免费播放放 | 在线播放精品一区二区三区 | 国产精品欧美久久久久久 | 午夜精品99久久免费 | 干干干操操操 | 日韩精品一区电影 | 亚洲日b视频 | 亚洲精选国产 | 久久99精品久久久久久久久久久久 | 国产精品乱码久久久久久1区2区 | 98久9在线 | 免费 | 欧美激情在线网站 | 欧美日韩免费看 | 免费黄色看片 | 色九色| 国产精品久久久久永久免费观看 | 在线观看视频免费播放 | 国产一级精品视频 | 中文字幕丝袜 | 国产精品中文在线 | 在线观看国产日韩欧美 | 亚洲综合激情小说 | 91热在线| 色www.| 涩涩色亚洲一区 | 国产亚洲久一区二区 | 日日夜夜天天人人 | 91亚洲精品乱码久久久久久蜜桃 | 久草视频在线免费看 | 久久综合中文字幕 | 视频一区在线播放 | 日韩视频1区 | 欧美激情h | 色综合www| 最近免费观看的电影完整版 | 国产视频一区在线 | 日韩理论片| av中文字幕在线免费观看 | 在线成人av | 最新日本中文字幕 | 国产麻豆精品一区二区 | 亚洲精品久久久久久久不卡四虎 | 日韩乱色精品一区二区 | 天天色棕合合合合合合 | 日韩,精品电影 | av色综合| 在线激情小视频 | 国产无吗一区二区三区在线欢 | 久久综合久久综合久久 | 欧美亚洲精品在线观看 | 欧美日韩精品电影 | 色www. | 成人四虎| 成人啊 v | 国产精品久久久久久久久久妇女 | 午夜精品一区二区三区可下载 | 日韩中文在线视频 | 亚洲欧洲av| 黄色片网站av | 国产91精品一区二区绿帽 | 亚洲最新合集 | 久久色网站 | 国产探花视频在线播放 | 在线 高清 中文字幕 | 一区二区三区免费在线 | 91中文在线 | 天天添夜夜操 | 国产色在线观看 | 亚洲专区中文字幕 | av韩国在线 | 国产精品一区免费观看 | a视频在线| av在线免费观看网站 | 五月天婷婷免费视频 | 精品一区二区三区久久久 | 手机成人av在线 | 主播av在线 | 亚洲精品九九 | 久久艹在线 | 国产成人精品一区二区三区在线 | 久久久av电影 | 国产精品自产拍在线观看中文 | 特级西西444www大胆高清无视频 | 色无五月| 亚洲第五色综合网 | 免费福利在线播放 | 亚洲伊人成综合网 | 天天操天天爽天天干 | 精品国产一区二区三区久久 | 成人欧美一区二区三区黑人麻豆 | 中文字幕精品一区二区三区电影 | 亚洲午夜精品久久久久久久久久久久 | 五月激情天| 亚洲精品高清在线 | 日韩免费成人av | 91精品久久久久久久久久入口 | 99色婷婷 | 午夜精品一区二区三区视频免费看 | 在线观看黄色免费视频 | 91视频免费看片 | 亚洲一级理论片 | 国产精品午夜久久 | 91黄视频在线观看 | 日日干夜夜干 | 91天堂素人约啪 | 狠狠干在线播放 | 激情五月综合网 | 亚洲精品高清一区二区三区四区 | 国产精品久久久久久久久久妇女 | 日韩精品一区二区在线视频 | 五月天激情电影 | 色婷婷综合视频在线观看 | 在线观看日本高清mv视频 | 日韩色爱| 日韩在线视频免费播放 | 免费高清在线观看电视网站 | 主播av在线| 天天干天天做 | 最新精品视频在线 | 日韩二区在线观看 | 亚洲精品网站在线 | 人人dvd | 日韩免费在线观看视频 | 国产精品999久久久 久产久精国产品 | 日韩av不卡在线观看 | 久久99久久99精品免观看软件 | 亚洲va欧美va | 在线观看深夜视频 | 成片视频在线观看 | 日韩电影中文字幕在线观看 | www色婷婷com | 国产专区一 | 成人免费 在线播放 | 成年人看片网站 | 国产专区日韩专区 | 午夜av免费看 | 制服丝袜成人在线 | 中文字幕大全 | 在线天堂日本 | 日本天天操 | 五月天色婷婷丁香 | 99r在线观看 | 久久久91精品国产一区二区精品 | 日韩v在线 | 不卡的av在线| 久久精品欧美日韩精品 | 国产精品综合av一区二区国产馆 | 日韩中文在线字幕 | 91成年视频 | 国产超碰在线 | 亚洲精品一区二区三区在线观看 | 97国产大学生情侣白嫩酒店 | 免费开视频 | 涩涩网站免费 | 欧美极品少妇xbxb性爽爽视频 | 日韩欧美国产激情在线播放 | 日韩精品在线观看av | 深爱五月激情五月 | 一区二区三区久久 | 日韩在线中文字幕视频 | 亚洲国产精品99久久久久久久久 | 中国一级片在线 | 欧美性色黄| 麻豆视频国产在线观看 | 日韩欧美一区二区在线观看 | 日韩av在线看 | 99在线精品视频在线观看 | 91视频高清完整版 | 国产在线观看国语版免费 | 日韩美女免费线视频 | 国产精品久久亚洲 | 91亚洲精品国产 | 夜夜夜夜夜夜操 | 91久久国产自产拍夜夜嗨 | 国产一二三精品 | 亚洲一区免费在线 | 99999精品| 免费黄色在线 | 精品美女在线视频 | 午夜天天操| 91尤物国产尤物福利在线播放 | 亚洲一级电影视频 | 欧美日韩大片在线观看 | 久久草在线视频国产 | 亚洲色图美腿丝袜 | 91夫妻视频 | 久久99精品国产一区二区三区 | 久久精品激情 | 久久久福利视频 | 成人免费一级片 | 欧美成人tv | 夜夜爽夜夜操 | 亚洲精品国产精品国自产观看浪潮 | 久久国产精品99久久人人澡 | 欧美999| 欧美三级高清 | 悠悠av资源片 | 国产一区视频在线播放 | av福利在线导航 | 精品91在线 | 天天草夜夜 | 国产精品手机在线播放 | 在线视频 精品 | 亚洲精品美女 | 色综合久久久久久久 | 人人看人人爱 | 99久久综合狠狠综合久久 | 麻豆免费视频网站 | 亚洲va欧美va | 欧美激情第一页xxx 午夜性福利 | av免费观看网站 | 三级av小说| 激情视频国产 | 国产精品毛片一区二区在线 | 天天操天天操天天操天天 | 91桃色国产在线播放 | 亚洲精品中文在线 | 免费观看www小视频的软件 | 91av视频在线观看 | 国产精品视频线看 | 亚洲精品国产精品国自产观看浪潮 | 午夜精品福利一区二区三区蜜桃 | 欧美性高跟鞋xxxxhd | 久久久免费少妇 | 免费精品视频在线 | 91理论电影| 久久久国产精品亚洲一区 | 久香蕉| 黄网站色视频免费观看 | 亚洲精品国产精品国 | 中日韩在线视频 | 97色噜噜 | 日韩欧美精品在线 | 日批视频在线播放 | 日本中文字幕网站 | 国产精品 日韩 欧美 | 97天堂网 | 亚洲毛片视频 | 色综合久久88色综合天天人守婷 | 久久免费视频1 | 九九热视频在线播放 | 青青草国产精品 | 欧美日韩一区二区三区在线观看视频 | 天天干天天怕 | 欧美精品久久久久久久久久 | 丁香电影小说免费视频观看 | 欧美精品久久久久久久久久久 | 国产a网站 | 免费高清在线视频一区· | adn—256中文在线观看 | 国产又粗又猛又色又黄网站 | 婷婷午夜| 久久高清免费观看 | 丁香电影小说免费视频观看 | 国产成人777777 | 免费精品国产va自在自线 | 亚洲精品视频二区 | 国产高清av在线播放 | 欧美一级激情 | 久久不见久久见免费影院 | 99视频在线精品国自产拍免费观看 | 久久免费一 | 深夜免费福利视频 | 亚洲成人国产 | 女人18片毛片90分钟 | 九色精品 | 嫩嫩影院理论片 | 中文字幕在线国产 | 丁香五月亚洲综合在线 | 日韩二区精品 | 亚洲精品国产精品99久久 | 久久久久国产精品免费免费搜索 | 久久大片网站 | 久久婷婷网 | 国产精品黄色影片导航在线观看 | av资源网在线播放 | 国产精品久久久久久久久搜平片 | 在线观看国产区 | 成人在线免费看 | 久久精品视频在线观看免费 | 99久久精品国产一区二区三区 | 婷婷在线看 | 国产精品久久久久久久久久不蜜月 | 91久久国产综合精品女同国语 | www.夜色321.com| 久久久久免费网 | 在线观看亚洲视频 | 国产黄视频在线观看 | 国产丝袜美腿在线 | 九九免费在线看完整版 | 久操免费视频 | 在线欧美最极品的av | 四虎成人免费影院 | 免费在线一区二区三区 | 成人av播放 | 久久久久国产精品免费 | 狠狠色噜噜狠狠狠合久 | 日本91在线 | 国产在线2020 | 亚洲精品无 | 亚洲 精品在线视频 | 黄在线免费看 | 国产精品成人一区 | 久久久久久久久久久久久久av | 我要看黄色一级片 | 久久精品成人热国产成 | 亚洲精品国偷拍自产在线观看 | 国产在线一线 | 中文字幕在线观看视频一区 | 高清免费在线视频 | 不卡精品视频 | 中文字幕乱码亚洲精品一区 | 国产综合在线观看视频 | 亚欧日韩av | 久草电影网| 97精品国自产拍在线观看 | 又色又爽又激情的59视频 | 日韩在线网址 | 国产成人精品免费在线观看 | 美女网站色在线观看 | 丁香九月激情综合 | 日韩精品视频免费在线观看 | 成人免费视频播放 | 久久网站最新地址 | 久久久在线免费观看 | 精品视频免费久久久看 | 日韩www在线 | 日韩69视频 | 少妇bbbb搡bbbb桶 | 96视频免费在线观看 | 在线播放av网址 | 超碰97公开 | 中文字幕国语官网在线视频 | 免费久久久 | 九九免费精品视频在线观看 | 国产美女久久 | 国产精品麻豆91 | 丁香婷婷在线 | 99久久婷婷国产精品综合 | 日本精品视频在线观看 | 国产99久久久国产精品 | av+在线播放在线播放 | 亚洲国产中文在线 | 国产黄色精品在线观看 | 国产精品毛片久久蜜 | 一级黄色片在线免费看 | 在线播放 日韩专区 | 超碰99在线| 91精品久久久久久综合乱菊 | 在线播放视频一区 | 黄色成人在线网站 | 国产精品24小时在线观看 | 日本中文在线 | 91福利小视频| 91精品一区二区在线观看 | 香蕉视频在线播放 | 日韩精品大片 | 久久国产精品一国产精品 | 日韩久久电影 | 欧美一级艳片视频免费观看 | 亚洲一区二区三区在线看 | 欧洲激情在线 | 天天色中文 | 狠狠天天 | 在线观看的av | 久久久免费看视频 | 中文亚洲欧美日韩 | 色婷婷av国产精品 | 国产精品va在线观看入 | 97视频久久久 | 国内精品久久久久久久 | 在线高清 | 一级欧美黄 | 色夜视频 | 99精品久久精品一区二区 | av电影中文字幕 | 日韩手机在线观看 | 狠狠干夜夜操天天爽 | 亚洲国产免费 | 2022国产精品视频 | 久艹在线免费观看 | 99热99| 国产成人在线一区 | 国产视频精品视频 | 成人午夜影视 | 波多野结衣在线观看一区二区三区 | 久久国产精品免费视频 | 成年人免费电影在线观看 | 亚洲一区精品人人爽人人躁 | 在线观看a视频 | 天天插综合网 | 日韩在线视 | 久久久久久久久久电影 | 国产一区视频在线观看免费 | 特黄色大片 | 日本一区二区不卡高清 | 91视频三区| 亚洲精品美女视频 | 国产中文字幕在线 | av中文字幕在线观看网站 | 国产精品久免费的黄网站 | 人人爽影院 | 最近免费中文字幕mv在线视频3 | 成年人视频在线免费播放 | 四虎在线免费视频 | 在线电影 一区 | 天天射天 | 国产专区一 | 91视视频在线直接观看在线看网页在线看 | av一级网站| 99久久婷婷国产精品综合 | 9i看片成人免费看片 | 欧美国产日韩一区二区三区 | 久久免费毛片视频 | 久久久国产电影 | 久久国产成人午夜av影院潦草 | 欧美精品国产综合久久 | 亚洲午夜久久久综合37日本 | 免费色网站 | 中文字幕第一页av | 免费观看的黄色片 | 中文字幕中文字幕 | 天天爱天天射天天干天天 | 久久久69 | 西西人体www444| 日本久草电影 | 人人澡人人草 | 久久免费视频1 | 国产亚州av | 一区二区三区四区五区在线 | 久久精品99久久久久久 | www.777奇米| 免费国产视频 | www.夜夜干.com| 欧美伦理一区 | 成人国产精品一区二区 | 福利视频网址 | 久草在线免费看视频 | 欧美精品三级 | 亚洲午夜av久久乱码 | 超碰国产人人 | 国产原创在线视频 | 天堂在线一区 | 狠狠久久婷婷 | 99在线免费观看视频 | 手机成人av | 日韩免费电影一区二区三区 | 久久乐九色婷婷综合色狠狠182 | 丁香婷婷色综合亚洲电影 | 国产成人精品av | 亚洲欧洲在线视频 | 日韩一二三| 亚洲国产精品一区二区久久,亚洲午夜 | 成人午夜剧场在线观看 | 欧美日韩亚洲第一 | 欧美做受高潮电影o | 91精品国自产在线观看 | 国产蜜臀av | 日韩最新在线 | 国内精品美女在线观看 | 精品亚洲一区二区三区 | 中文字幕在线观看一区 | 黄色片亚洲| 日本少妇视频 | 黄色在线观看免费 | 在线观看一级视频 | 亚洲婷婷免费 | 蜜臀av网址 | 国产精彩视频一区二区 | 色综合久久88色综合天天人守婷 | 国产在线污 | 激情在线五月天 | 在线观看视频免费大全 | 国产中文字幕在线视频 | 久久99精品国产麻豆宅宅 | 免费高清在线观看成人 | 成人av网页| 欧美日韩aaaa | 日韩免费av网址 | 精品在线一区二区三区 | 成人91av| 国产精品白浆视频 | 最新av在线网址 | 毛片二区 | 欧洲一区二区三区精品 | av在线免费网 | 国产精品淫片 | 97在线观看免费高清 | 成人免费在线观看av | 久久国产精品99国产 | 一级片视频在线 | 欧美精品乱码99久久影院 | 亚洲国产成人精品久久 | 超碰97人人爱 | 一区二区国产精品 | 日韩午夜电影网 | 看片黄网站 | 97免费在线观看视频 | 成人在线观看日韩 | 中文字幕亚洲欧美日韩 | 国产 一区二区三区 在线 | 精品在线视频一区二区三区 | 在线观看黄色国产 | 久久在线电影 | 五月天激情在线 | 久久精品视频在线免费观看 | 玖玖视频精品 | 一区二区免费不卡在线 | 中文字幕之中文字幕 | av线上看 | 日日摸日日爽 | 欧美精品一级视频 | 天天干天天干天天色 | 亚洲美女精品区人人人人 | 激情视频网页 | 久久精品成人欧美大片古装 | 久久在线免费观看 | 91在线视频播放 | 日本在线精品视频 | 久久中文网 | 色综合久久精品 | 高潮毛片无遮挡高清免费 | 日韩影视大全 | 狠狠干天天色 | 欧美日韩电影在线播放 | 亚洲综合视频在线播放 | 天天操天天射天天插 | 在线免费观看成人 | 在线91观看 | 五月婷婷在线观看视频 | 日韩精品在线视频 | 91在线视频免费播放 | 国产麻豆精品传媒av国产下载 | 国产又黄又爽又猛视频日本 | 亚洲狠狠丁香婷婷综合久久久 | 亚洲精品观看 | 婷婷色综合 | 国产精品涩涩屋www在线观看 | 在线观看精品国产 | 免费看的黄网站软件 | 天天草综合网 | 啪啪小视频网站 | 日韩在线观看电影 | 黄色精品网站 | 日本中文字幕在线观看 | 狠狠操操网| 亚洲成人999| 久久网址 | 波多野结衣一区二区三区中文字幕 | 91免费网站在线观看 | 蜜桃av久久久亚洲精品 | 亚洲国产视频在线 | 天天草视频 | 亚洲欧美经典 | 一级欧美一级日韩 | 成人在线视频免费看 | 天天av在线播放 | 97成人免费 | 天天玩天天操天天射 | 开心色婷婷 | 二区视频在线观看 | 亚洲一一在线 | 97超碰在线久草超碰在线观看 | 免费观看久久 | 操老逼免费视频 | 国产精品都在这里 | 免费视频 你懂的 | 亚洲视频免费在线看 | 国产精品资源 | 欧美在线观看视频 | 亚洲乱码一区 | 一区二区三区四区久久 | 91成人看片| 中文字幕在线一区二区三区 | 天天操天天射天天插 | 欧美精品中文字幕亚洲专区 | 91精品999| 五月综合婷 | 91精品国产成人 | 特级西西人体444是什么意思 | 91禁看片| 九九免费精品视频在线观看 | 天天综合天天综合 | 国产精品欧美精品 | 激情影院在线观看 | 色姑娘综合网 | 在线成人中文字幕 | 天天射天天干天天爽 | 婷婷激情网站 | 国产日产高清dvd碟片 | 国产电影黄色av | 国产91精品看黄网站在线观看动漫 | 国产精品久久一区二区无卡 | 久久国色夜色精品国产 | 激情www| 久久99亚洲精品久久久久 | 国产特级毛片aaaaaa毛片 | 免费在线色视频 | 国产精品久久久久久久久久三级 | 操一草 | 最新免费中文字幕 | 国产午夜一级毛片 | 成人国产精品免费观看 | 一区国产精品 | 亚洲精品久久久久中文字幕m男 | 在线а√天堂中文官网 | 在线观看中文 | 99精品在线直播 | 人人爽人人爽人人片 | 国产精品手机在线观看 | 国产精品久久久久久久久久新婚 | 亚洲精品动漫在线 | 韩国视频一区二区三区 | 一区二区视频电影在线观看 | 国产成人一区二区三区在线观看 | 国产高清中文字幕 | 亚洲成av人片在线观看www | 国产精品va在线播放 | 精品国产乱码久久久久久浪潮 | 91免费高清视频 | 久在线| 在线黄色av | 久久色视频| 国产流白浆高潮在线观看 | 国产精品99久久免费黑人 | 欧美日韩精品电影 | 久久99国产精品久久99 | 午夜三级在线 | 91精品视频在线免费观看 | 麻豆精品视频 | 波多野结衣最新 | 香蕉视频网站在线观看 | 91av在线视频免费观看 | 久久不射网站 | 久九视频| 日日干天天爽 | 日韩精品在线播放 | 999ZYZ玖玖资源站永久 | 欧美国产日韩一区二区三区 | 欧美日韩国产一区二区三区在线观看 | 欧美日韩1区| 中文字幕免费观看 | 中文日韩在线 | 亚洲另类视频在线观看 | 日女人电影 |