Java咖啡館(6)——編寫猜數字遊戲

  上一回我們講解了Java語言基礎,篇幅所限,僅僅包含相當有限的Java語法知識。本期我們將在上回基礎上編寫一個猜數字的遊戲,進一步學習Java語言基礎知識。

猜數字遊戲

  你肯定玩過猜數字遊戲—遊戲隨機給出一個0至99(包括0和99)之間的數字,然後讓你猜是什麼數字。你可以隨便猜一個數字,遊戲會提示太大還是太小,從而縮小結果範圍。經過幾次猜測與提示後,最終推出答案(我們提供了完整代碼,點擊這裏下載)。(見圖1)

遊戲設計

  首先搭建Java程序框架。打開Eclipse,新建名爲GuessNumberGame的項目,然後新建名爲GuessNumber的Java類。別忘記給GuessNumber加上合適的javadoc。

  第一步:隨機數的產生

  我們可以藉助Java API提供的Random類來產生一個隨機數。

  首先在main函數中加入以下三行代碼:

// 新建一個隨機數產生器,然後生成一個0到99之間的整數。
Random random = new Random();
int number = random.nextInt(100);

  不出所料,Eclipse就像語文老師一樣,立即在錯誤語句處劃出紅線,把鼠標移動到紅線上,可以看到具體出錯信息(見圖2)。

  包(Package)的概念

  Java API中包含了極其豐富、類似於Random這樣由Sun預先定義好的類(Class,如果忘記相關概念,請參考第四篇連載—《品味第一杯咖啡》),與變量作用域的問題一樣,不同包中可以有同名同姓的類,如果沒有包的概念,就會遇到命名衝突問題。此外,包還能進行安全控制,你可以規定哪些類可以被包外部調用,哪些不可以。

  Random類是在java.util這個包中。可以手動在源程序頂部輸入import java.util.Random;語句來申明該程序將要使用java.util包中的Random類,然而有了Eclipse,就不用那麼麻煩了—把光標移動到有紅色波浪線的Random上,然後按下Ctrl+Shift+M,Eclipse會自動幫你完成導入的工作了。此時保存一下源代碼,警告是不是消失了?希望你牢記這個快捷鍵的用法,在開發大型項目時,再好的腦子也無法牢記每個類所在的包的名字,有了Eclipse的鼎力相助,偷個懶也沒問題。

  語句翻譯

  第一句定義了一個類型是Random類的變量random(Java語言區分大小寫,所以Random和random是兩回事兒),並且用new操作符生成一個Random類的實例賦給random變量。還記得我們上期連載說到變量還有一種引用類型嗎?這就是一個例子。random變量實際上是一個參照,指向內存中用new操作符新建的Random類的實例。說起來很拗口,大多數情況下可以把random直接看做是一個Random類的實例,可以通過“random”加上“.操作符”來調用Random類的方法,比如用random.nextInt(100)來獲取一個0至99之間的隨機數。

  第二句語句定義一個整型變量number來保存隨機產生的整數,並且用直接初始化的方法把random產生的隨機數賦給number變量。

  第二步:標準輸入輸出

  標準輸入輸出(Standard I/O)是指可以被應用程序使用的信息流。比如,應用程序可以從標準輸入(Standard input)讀取數據,向標準輸出(Standard output)寫數據,把出錯信息發送到標準錯誤(Standard error)。通過輸入輸出,應用程序和應用程序之間可以被串聯起來使用。雖然標準輸入輸出是從UNIX發展出來的概念,在Windows中也廣泛應用,如果你熟悉DOS,這個概念自然不陌生。
猜數字遊戲主要用到標準輸入,更明確一些,就是控制檯輸入。還記得我們經常使用System.out.println進行控制檯輸出嗎?相反,要從控制檯輸入,就需要用到System.in。它是一個純粹的輸入流,而猜數字遊戲主要是通過控制檯獲取玩家的字符(特別是能夠支持多國語言的Unicode字符)輸入,我們需要把它包裝成一個BufferedReader實例來使用:

BufferedReader input = new BufferedReader(
new InputStreamReader(System.in));

  這時,input就是一個能處理來自控制檯輸入的、支持Unicode的、可以整行讀取的一個BufferedReader實例,比如能通過input.readLine()方法獲取玩家在控制檯整整一行的輸入了。

  第三步:異常

  正如阿甘的名言—Shit happens,程序中的金科玉律就是—一定會出錯。出錯並不可怕,關鍵看如何對待錯誤,有錯必究才善莫大焉。

  Java語言提供了異常(Exception)處理機制幫助程序員發現並處理異常。什麼是異常呢?所謂異常,就是在程序執行過程中能干擾程序正常流程的事件。導致異常的原因很多,比如文件找不到、數組越界、除以零等。當異常出現時,一個異常對象將被自動生成並傳遞給Java“運行時環境”(runtime system),說得專業一點,就是拋出一個異常。異常對象包含了異常類型、程序運行狀態等信息。“運行時環境”得到異常對象後便打斷程序的正常流程,自動尋找一個專門處理該異常的代碼塊來解決問題。這樣的代碼塊稱作異常句柄(Exception Handler)。你可以在異常句柄中嘗試修復錯誤、重試或者報錯,或者實在無法進行下去的時候來個自我了斷。如果“運行時環境”找不到異常句柄,Java程序便會自行中斷。

  一個典型的異常處理是這個樣子的:

try {
statement(s);
} catch (exceptiontype1 name) {
statement(s);
} catch (exceptiontype2 name) {
statement(s);
} finally {
statement(s);
}

  其中:

  ★try語句括起來的語句可能拋出異常。try語句至少要搭配一個catch語句或finally語句,不能單獨使用。
  ★catch語句必須和一個try語句配套使用,根據異常類型(exception type)分別處理不同的異常。也就是說,Java有許多預先定義的異常,你可以通過多個catch語句對它們分門別類地處理。你還可以自己定義異常類型。如果try語句塊中沒有拋出異常,這裏自然不會被執行。
  ★finally語句也必須和一個try語句配套使用,與catch語句不同,無論try語句塊中是否拋出異常,finally所包括的語句塊都會被執行。

  舉個具體的例子來熟悉一下。猜數字遊戲需要從控制檯獲取玩家輸入的數字。我們先定義一個整型變量:

int guess;

  然後就可以編寫如下代碼:

guess = Integer.parseInt(input.readLine());

  通過input.readLine從控制檯讀取輸入,並且用Integer.parseInt把獲取的字符串類型的輸入轉換成整型,然後賦給guess變量。

  Eclipse又給你臉色看了——input.readLine()下面劃上了紅線(見圖3)。

  看看提示,原來是未處理異常句柄。

  原來,Java有一種異常稱作檢查型異常(Checked Exceptions)。一般數組越界、除以零等等都是運行時異常,由於數量衆多,Java允許你不必親自捕捉每個這樣的異常,而全權交給運行時環境去處理。但檢查型異常就不一樣了,Java把檢查型異常提升到與參數、返回值同樣的高度,也就是說,檢查型異常你非處理不可,並且在javadoc中必須加以註釋。

  那麼怎樣快速地捕捉這樣的異常呢?按照如圖3所示,用鼠標點擊帶有紅叉的燈泡圖標,在彈出菜單上選擇Surround with Try/Catch,異常處理代碼模塊立即自動生成了。可以發現,這一句話將拋出兩個異常:一個是格式異常(NumberFormatException),因爲如果你用Integer.parseInt去轉換一個漢字,自然是不可能的。另一個便是I/O異常,即標準輸入可能會出現不可預料的問題。怎麼樣,連異常都能夠自動捕捉,這就是Eclipse的魅力!

  需要說明的是,NumberFormatException並不是檢查型異常,而是一個不必刻意捕捉的運行時異常。試試看把捕捉NumberFormatException的那個catch語句塊全部刪除,Eclipse也不會報錯。不過,捕捉這個異常很有實用價值,後文的代碼會進一步展示它的作用。

  小提示

  使用異常機制的諸多好處

  ★使得程序更健壯,界面更友善。
  ★把程序的業務邏輯與錯誤處理分開,代碼更合理,更美觀。
  ★異常可以分層次處理,使得代碼更簡潔。
  ★同類的異常可以歸到一類一起處理,處理更方便。

  Java的異常處理機制是一個很大的話題,這裏僅僅是展示了冰山一角,以實用爲主,希望你能夠自行閱讀擴展知識,並且在編寫代碼過程中注意體會。

  while循環控制

  上回的Java咖啡館介紹了for循環語句,這回需要介紹一個它的“親戚”語句——while語句。

  while語句的語法是:

while ( expression ) {
statement(s)
}

  首先,while語句判斷返回一個布爾值的expression表達式,如果返回值爲true,則執行下面語句,之後再測試expression表達式再執行語句,以此往復,直到expression表達式返回false爲止。

do-while語句與while語句非常相似,語法是:

do {
statement(s)
} while ( expression );

  與while語句在循環頂部判斷表達式真假值不同,do-while語句在底部判斷,從而,do-while語句至少執行一次內部的代碼。

  下面看看猜數字遊戲的主體部分:

// 記錄玩家猜測的次數
int counter = 0;
System.out.println("我心裏有一個0到99之間的整數,你猜是什麼?");

do {
try {
// 獲取玩家的輸入
guess = Integer.parseInt(input.readLine());
} catch (NumberFormatException e) {
// 如果玩家不是輸入一個合法的整數,則讓他重新輸入
System.out.println("請輸入一個0-99之間的整數!");
continue;
} catch (IOException e) {
System.out.println("程序發生異常錯誤將被關閉!");
e.printStackTrace();
}

// 對玩家的輸入進行判斷
if (guess > number)
System.out.println("大了點,再猜!");
if (guess < number)
System.out.println("小了點,再試試!");

// 計數器增加一
counter++;
} while (guess != number);

  首先定義了一個counter變量來記錄玩家猜測的次數,並直接初始化爲0。在打印一行遊戲提示以後,便開始一個do-while語句。

  在do-while語句中,首先用異常處理語句獲取玩家的輸入,如果玩家輸入不合法,提示以後用continue語句從頭重新執行循環語句,等待玩家的輸入。從而,guess變量一定包含一個合法的整數。之後要對玩家的輸入進行判斷。如果玩家的猜測太大或者太小,都做出提示。接着把計數器增加1,表示玩家做過一次猜測。最後便是do-while語句的判斷:當玩家猜測的數字和隨機產生的答案不同,則再次進入循環,否則便結束循環,執行下面的代碼。

  最後提醒一句,別忘記用Eclipse的Alt+/快捷鍵幫助編寫do-while語句哦!

  switch語句

  switch語句是基於整型表達式的條件判斷語句,猜數字用它來進行成績判斷:

// 判斷成績
switch (counter) {
case 1:
System.out.println("東漸……快來看上帝……");
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
System.out.println("這麼快就猜對了,你很smart啊!");
break;
default:
System.out.println("猜了半天才猜出來,小同志,尚須努力啊!");
break;
}

  可以看出,switch語句是和若干case語句和一個default語句搭配使用的。代碼中的switch語句用counter變量的值進行判斷。當counter的值爲1時,便執行case 1裏面的語句,即打印“東漸……快來看上帝……”的字樣,隨後的break語句表示整個switch語句執行到這裏結束了。當counter的值爲2時,便執行case 2裏面的語句。可以發現case 2到case 6都沒有break語句,這表示依次執行下面的語句,從而counter的值爲2至7時,都打印“這麼快就猜對了,你很smart啊!”字樣。當counter的值不是1至7時,便執行default語句,打印鼓勵的話語。

  Just Do It

  想想看怎樣編寫一個會玩猜數字遊戲的Java程序呢?

  小結

  這是Java咖啡館開張以來最漫長的一回,涉及的知識面很廣,希望你能夠感到充實而不是煩瑣。此外,自己動手編寫幾個小程序是最好的練習方法。Eclipse是良師益友,有什麼問題都會及時通知你,有時還會附上解決方法,希望你善加利用,不要辜負一片心意哦。 

發佈了3 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章