- Java從入門到精通(第2版)
- 龍馬高新教育策劃 魔樂科技(MLDN)軟件實訓中心編著 張玉宏主編
- 1305字
- 2019-01-02 04:58:45
第3章 初識廬山真面目—Java程序要素概覽
本章視頻教學錄像:1 小時33分鐘
麻雀雖小,五臟俱全。本章的實例雖然非常簡單,但基本涵蓋了本篇所講的內容。可以通過本章來概覽Java程序的組成及內部部件(如Java中的標識符、關鍵字、變量、注釋等)。同時,本章還涉及到Java程序錯誤的檢測及Java編程風格的注意事項。
本章要點(已掌握的在方框中打鉤)
□ 掌握Java程序的組成
□ 掌握Java 程序注釋的使用
□ 掌握Java 中的標識符和關鍵字
□ 了解Java 中的變量及其設置
□ 了解程序的檢測
□ 掌握提高程序可讀性的方法
3.1 一個簡單的例子
本節視頻教學錄像:15分鐘
從本章開始,我們正式學習Java語言的程序設計。除了認識程序的架構外,本章還將介紹修飾符、關鍵字以及一些基本的數據類型。通過簡單的范例,讓讀者了解到檢測與提高程序可讀性的方法,以培養讀者良好的編程風格和正確的程序編寫習慣。
下面來看一個簡單的Java程序。在介紹程序之前,讀者先簡單回顧一下第1章講解的例子,之后再來看下面的這個程序,在此基礎上理解此程序的主要功能。
【范例3-1】 Java程序簡單范例(代碼TestJava3 1.java)。
01 /** 02 03 *@ClassName:TestJava3_1 04 05 *@Description:這是Java的一個簡單范例 06 07 *@author:YuHong&Kerl 08 09 *@date:2014年1月14日下午9:40:39 10 11 */ 12 public class TestJava3_1 13 { 14 public static void main(String args[]) 15 { 16 int num; //聲明一個整型變量num 17 num=5; //將整型變量賦值為3 18 //輸出字符串,這里用"+"號連接變量 19 System.out.println("這是數字"+num); 20 System.out.println("我有"+num+"本書!"); 21 } 22 }
【運行結果】
保存并運行程序,結果如下圖所示,注意該圖由Eclipse軟件輸出的界面,Eclipse軟件的使用方法讀者參閱第2章。

如果讀者現在暫時看不懂上面的這個程序,也沒有關系,先把這些Java代碼在任意文本編輯器里(Eclipse編輯器、微軟的寫字板、Notepad++等均可)手工敲出來(盡量不要用拷貝+復制的模式來完成代碼輸入,每一次編程上的犯錯,糾正之后,都是進步!),然后存盤、編譯、運行,就可以看到輸出結果。
【代碼詳解】
首先說明的是,例3-1中的行號是為了讓讀者(程序員)便于理解而人為添加的,真正Java源代碼是沒有這些行號的。
第1-11行為程序的注釋, 會被編譯器自動過濾。但通過注釋可以提高Java源碼的可讀性,使得Java程序條理清晰。需要說明的是,第1-11行有部分空白行,空白行同樣會被編譯器過濾,在這里的主要功能是為了代碼的美觀。編寫程序到了一定的境界,程序員不僅要追求程序功能的實現,還要追求源代碼外在的“美”。這是一種編程風格,“美”的定義和理解不同,編程風格也各異。
第12行 public class TestJava3_1中的public與class是Java的關鍵字,class為“類”的意思,后面接上類名稱,在本程序中取名為TestJava3_1。public則是用來表示該類為公有,也就是在整個程序里都可以訪問到它。
需要特別注意的是:如果將一個類聲明成public,那么需保證文件名稱和這個類名稱相同,如下圖所示。本例中的文件名為TestJava3_1.java,而public之后所接的類名稱也為TestJava3_1。也就是說,在一個Java文件里,最多只能有一個public類,否則.java的文件便無法命名。

第14行public static void main(String args[ ])為程序運行的起點。第15~21行({}花括號之內)的功能類似于一般程序語言中的函數(function),但在Java中稱之為method(方法)。因此C語言里的main()函數(主函數),在Java中則被稱為main()方法(主方法)。
main()方法的主體(body)從第15行的左大括號“{”到第21行的右大括號“}”為止。每一個獨立的Java程序一定要有main()方法才能運行,因為它是程序開始運行的起點。
第16行“int num”的目的是聲明num為一個整數類型的變量。在使用變量之前,必須先聲明其數據類型。
第17行“num=3”為一賦值語句,即把整數3賦給存放整數的變量num。
第19行的語句如下。
19 System.out.println("這是數字"+num);
程序運行時會在顯示器上輸出引號(")內所包含的內容,包括“這是數字”和整數變量num所存放的值。
System.out是指標準輸出,通常與計算機的接口設備有關,如打印機、顯示器等。其后所續的println,是由print與line所組成的,意思是將后面括號中的內容打印在標準輸出設備——顯示器上。因此第19行的語句執行完后會換行,也就是把光標移到下一行的開頭繼續輸出。類似的方法還有System.out.print(),同System.out.println()相比,System.out.print()輸出指定內容,但不換行。讀者可以把System.out.println()改成System.out.print(),看一下換行與不換行的區別。
第21行的右大括號告訴編譯器main() method到這兒結束。
第22行的右大括號告訴編譯器class TestJava3_1到這兒結束。
這里只是簡單地介紹了一下TestJava3_1這個程序,相信讀者已經對Java語言有了一個初步的了解。TestJava3_1程序雖然很短,卻是一個相當完整的Java程序。在后面的章節中,將會對Java語言的細節部分做詳細的討論。
3.2 感性認識Java程序
在本節,我們將探討Java語言的一些基本規則及用法。
本節視頻教學錄像:54分鐘
3.2.1 認識Java程序的框架
1. 大括號、段及主體
將類名稱定出之后,就可以開始編寫類的內容。左大括號“{”為類的主體開始標記,而整個類的主體至右大括號“}”結束。每個命令語句結束時,都必須以分號“;”做結尾。當某個命令的語句不止一行時,必須以一對大括號“{}”將這些語句包括起來,形成一個程序段(segment)或是塊(block)。
下面以一個簡單的程序為例來說明什么是段與主體(body)。若暫時看不懂TestJava3_2這個程序,也不用擔心,以后會講到該程序中所用到的命令。
【范例3-2】 簡單的Java程序(TestJava3 2.java)。
01 //TestJava3_2,簡單的Java程序 02 public class TestJava3_2 03 { 04 public static void main(String args[]) 05 { 06 int x; 07 for(x=1;x<3;x++) 08 { 09 System.out.println(x+"*"+x+"="+x*x); 10 } 11 } 12 }
【運行結果】
運行程序并保存,結果如下圖所示。

【范例分析】
在上面的程序中,可以看到main() 方法的主體以左右大括號{}包圍起來;for循環中的語句不止一行,所以使用左右大括號{}將屬于for循環的段內容包圍起來;類TestJava3_2的內容又被第3行與第12行的左右大括號{}包圍,這個塊屬于public類TestJava3_2所有。此外,應注意到每個語句結束時,都是以分號“;”作為結尾。
2. 程序運行的起始點 —— main() 方法
Java程序是由一個或一個以上的類組合而成,程序起始的主體也是被包含在類之中。這個起始的地方稱為main(),用左右大括號將屬于main()段的內容包圍起來,稱之為“方法”(method)。
main()方法為程序的主方法,如同中國的古話“家有千口,主事一人”。類似的,在一個Java程序中,不論它有千萬行,執行的入口只能有一個,而這個執行的入口就是main()方法,它有且僅有一個。通常看到的main() 方法如下面的語句片段所示。
public static void main(String args[]) //main()方法,主程序開始 { … }
如前一節所述,main() 方法之前必須加上public static void 這3個標識符。public代表main()公有的方法;static表示main()是個靜態方法,可以不依賴對象而存在,也就是說,在沒有創建類的對象情況下,仍然可以執行;void英文本意為空的,這里表示main()方法沒有返回值。main后面括號()中的參數String args[]表示運行該程序時所需要的參數,這是固定的用法,我們會在以后的章節介紹這個參數的使用細節。
我們在學習Java中經常遇到“方法”這個概念,而在學習C語言或者C++中,又會遇到“函數”概念,語言都是相通的,那二者又有什么區別和聯系呢?
⑴ “函數”是一段實現某種“功能”的代碼,函數的操作是對輸入數據的處理。函數的英文“function”恰恰有“功能”的含義,可以達到“見名知意”。通過函數的名稱來實施函數調用。它能將一些數據(也就是參數)傳遞進去進行處理,然后返回一些數據(即函數的返回值),也可以沒有返回值。所有傳遞給函數的數據都是顯式傳遞的。而方法的參數傳遞通常是隱式的,它可以直接操作類內部的數據。
⑵ “方法”也是一段完成某項功能的代碼,也通過名字來進行調用,但它依賴于某個特定的對象,例如,我們可以說“調用對象X的Y方法”,而不能“調用Y方法”。簡單來講, 方法和對象相關;而函數和對象無關。因為Java是一門完全面向對象編程的語言,所以在Java里只有方法。
C語言是面向過程的編程語言,所以在C語言中只有函數。C++是C語言的超集,既支持面向過程編程,又支持面向對象編程,所以在C++中,如果一個函數獨立于類之外,那它就是函數,如果它存在于一個類中,那它就是方法,所不同的是,C++給這種特殊的方法取了一個新名稱——成員函數(member function)。
3.2.2 認識標識符
Java中的包(package)、類、方法、參數和變量的名稱,可由任意順序的大小寫字母、數字、下劃線(_)和美元符號($)等組成,但這些名稱的標識符不能以數字開頭,也不能是Java中保留的關鍵字。
下面是合法的標識符。
yourname your_name _yourname $yourname
比如,下面的4個標識符是非法的。
class 6num23 abc@sina x+y
非法的原因分別是:class是Java的保留關鍵字;6num23的首字母為數字;abc@sina中不能包含@等特殊字符;x+y不能包含運算符。此外,讀者應該注意,在Java中,標識符是區分大小寫的,也就是說,A123和a123是兩個完全不同的標識符。
注意
標識符的命名規則屬于強制性的,不然編譯時會報錯。一些剛接觸編程語言的讀者可能會覺得記住上面的規則很麻煩,所以在這里提醒讀者,標識符最好永遠用字母開頭,而且盡量不要包含其他的符號。規則是必須遵守的,而規范是約定俗成的,鼓勵大家都遵守的。
3.2.3 認識關鍵字
和其他語言一樣,Java中也有許多關鍵字(Keywords,也叫保留字),如public、static、int等,這些關鍵字不能當做標識符使用。下表列出了Java中的關鍵字。在程序開發中一旦使用了這些關鍵字做標識符,編譯器在編譯時就會報錯,而對智能的編輯器(如Eclipse等)會在編寫代碼時自動提示這些語法錯誤。在后續的章節中,我們會慢慢學習它們的內涵和用法。

注:*表示該關鍵字尚未啟用;**表示在Java 1.2添加的;***表示在Java 1.3添加的;****表示在Java 5.0添加的。
注意
雖然goto、const在Java中并沒有任何意義,卻也是保留的關鍵字,與其他的關鍵字一樣,在程序里不能用來作為自定義的標識符,true、false、null等看起來像關鍵詞,實際上在Java中,它們僅僅是普通的字符串。Java中的所有關鍵字均由小寫字母構成。
3.2.4 認識注釋
注釋在源代碼中的地位非常重要,雖然注釋在編譯時被編譯器自動過濾掉,但為程序添加注釋可以解釋程序的某些語句的作用和功能,提高程序的可讀性。特別當編寫大型程序時,多人團隊合作,A程序員寫的程序B程序員可能很難看懂,而注釋能起到非常重要的溝通作用。所以本書強力建議讀者朋友養成寫注釋的好習慣。
Java里的注釋根據不同的用途分為以下3種類型。
⑴ 單行注釋。
⑵ 多行注釋。
⑶ 文檔注釋。
單行注釋,就是在注釋內容的前面加雙斜線(//),Java編譯器會忽略這部分信息。如下所示。
int num; //定義一個整數
多行注釋,就是在注釋內容的前面以單斜線加一個星形標記(/*)開頭,并在注釋內容末尾以一個星形標記加單斜線(*/)結束。當注釋內容超過一行時,一般可使用這種方法,如下所示。
/* int c = 10 ; int x = 5 ; */
文檔注釋,是以單斜線加兩個星形標記(/**)開頭,并以一個星形標記加單斜線(*/)結束。用這種方法注釋的內容會被解釋成程序的正式文檔,并能包含進如javadoc之類的工具生成的文檔里,用以說明該程序的層次結構及其方法。范例3-1中的第1-11行對源代碼的注釋屬于類別(3),通常在程序開頭加入作者,時間,版本,要實現的功能等內容注釋,方便后來的維護以及程序員的交流。本質上注釋類別(3)是(2)的一個特例,(3)中的第2個星號*可看作注釋的一部分。由于文檔注釋比較費篇幅,在后面的范例中,我們不再給出此類注釋,讀者可在隨書配備的光盤中看到注釋更為全面的源代碼。
提示
還可以用程序注釋來暫時屏蔽某些程序語句,讓編譯器暫時不要處理這部分語句,等到需要處理的時候,只需把注釋標記取消即可。這也是程序調試一種技巧。注釋在調試和后期的維護過程中也有重要作用,請讀者務必重視。
需要注意的是,第3至第6行的注釋中,每一行前都有一個*,其實這不是必需的,它們是注釋區域的一個“普通”字符而已,僅僅是為了注釋部分看起來更加美觀。前文我們已提到,實現一個程序的基本功能是不夠的,優秀的程序員還會讓自己的代碼看起來很“美”。
提示
撰寫注釋部分,看起來比較繁瑣。其實完全可借助Eclipse方便地生成漂亮的注釋。在Eclipse中選擇【窗口】【首選項】
【Java】
【代碼樣式】
【代碼模板】,設置好一些固定格式的注釋模板后,按Alt+ Shift+ J 組合鍵便可方便插入注釋。
3.2.5 認識變量
在Java程序設計中,變量(Variable)在程序語言中扮演著最基本的角色,它是存儲數據的載體。計算機中的變量是實際存在的數據。變量的數值可以被讀取和修改,它是一切計算的基礎。
與變量相對應的就是常量(Constant),顧名思義,常量是固定不變的量,其一旦被定義并賦初值后,它的值就不能再被改變。有關常量的知識介紹,請讀者參閱第4章的有關內容。
本節主要關注的是對變量的認知,接下來看看Java中變量的使用規則。Java變量使用和其他高級計算機語言一樣:先聲明,后使用。即必須實現聲明它想要保存數據的類型。
1. 變量的聲明
聲明一個變量的基本方式為:
數據類型 變量名;
另外,在定義變量的同時,給予該變量初始化,建議讀者使用這種聲明變量的風格。
數據類型 變量名 = 數值或表達式;
舉例來說,想在程序中聲明一個可存放整型的變量,這個變量的名稱為num。在程序中即可寫出如下所示的語句。
int num; //聲明num為整數變量
int為Java的關鍵字,代表基本數據類型——整型(Integer)。若要同時聲明多個整型的變量,可以像上面的語句一樣分別聲明它們,也可以把它們都寫在同一個語句中,每個變量之間以逗號分開。下面的變量聲明的方式都是合法的。
int num1,num2,num3; //聲明三個變量num1,num2,num3,彼此用英文逗號“,”隔開 int num1;int num2;int num3; //用三個語句聲明上面的三個變量,彼此用英文分號“;”隔開
雖然上面兩種定義多個變量的語句都是合法的,但對它們添加注釋不甚方便,特別是對后一種同一行有多個語句,由于可讀性不好,建議讀者不要采納此種編程風格。
2. 變量名稱
讀者可以依據個人的喜好來決定變量的名稱,但這些變量的名稱不能使用Java的關鍵字。通常會以變量所代表的意義來取名。當然也可以使用a、b、c等簡單的英文字母代表變量,但是當程序很大時,需要的變量數量會很多,這些簡單名稱所代表的意義就比較容易忘記,必然會增加閱讀及調試程序的困難度。變量的命名之美在于:在符合變量命名規則的前提下,盡量對變量做到“見名知意”,如:用num 表示數字,用length 表示高度等。
3. 變量的設置
給所聲明的變量賦予一個屬于它的值,用賦值運算符(=)來實現。具體可使用如下所示的3種方法進行設置。
⑴ 在聲明變量時設置。
舉例來說,在程序中聲明一個整數的變量num,并直接把這個變量賦值為2 ,可以在程序中寫出如下的語句。
int num=2; //聲明變量,并直接設置
⑵ 聲明后再設置。
一般來說也可以在聲明后再給變量賦值。舉例來說,在程序中聲明整型變量num1、num2及字符變量ch,并且給它們分別賦值,在程序中即可寫出下面的語句。
int num1,num2; //聲明兩個整型變量num1和num2 char ch; //聲明一個字符變量ch num1=2; //將變量num1賦值為2 num2=3; //將變量num2賦值為3 ch='z'; //將字符變量ch賦值為字母z
⑶ 在程序的任何位置聲明并設置。
以聲明一個整數的變量num為例,可以等到要使用這個變量時再給它賦值。
int num; //聲明整型變量num … num=2; //用到變量num時,再賦值
3.2.6 認識數據類型
除了整數類型之外,Java還提供有多種數據類型。Java的變量類型可以是整型(int)、長整型(long)、短整型(short)、浮點型(float)、雙精度浮點型(double),或者字符型(char)和字符串型(String)等。下面對Java中的基本數據類型給予簡要介紹,讀者可參閱相關章節獲得更為詳細的介紹,基本數據類型的使用可參閱第5章;用戶自定義數據類型(class)的使用可參閱第9章;String類型的使用可參閱第16章。
整型是取值為不含小數的數據類型,包括byte類型、short類型、int類型及long類型,默認情況下為int類型,可用八進制、十進制及十六進制來表示。另一種存儲實數的類型是浮點型數據,主要包括float型(單精度浮點型,占4個字節)和double型(雙精度浮點型,占8個字節)。用來表示含有小數點的數據,必須聲明為浮點型。在默認情況下,浮點數是double型的。如果需要將某個包括小數點的實數聲明為單精度,則需要在該數值后加字母‘F’(或小寫字母‘f’)。
下面的語句是主要數據類型的定義說明。
01 int num1=10;//定義4字節大小的整型變量num1,并賦初值為10 02 byte age=20; //定義1個字節型變量age,并賦初值為20 03 //byte age2=129; //錯誤:超出了byte類型表示的最大范圍(-128~127)
04 float price=12.5f; //定義4字節的單精度float型變量price,并賦初值為12.5 05 float price=12.5; //錯誤:類型不匹配 06 double weight=12.5;//定義8字節的單精度float型變量weight,并賦初值為12.5
定義數據類型時,要注意兩點。
⑴ 在定義變量后,對變量賦值時,賦值大小不能超過所定義變量的表示范圍。例如,在本例第3行是錯誤的,給age2賦值129,已超出了byte類型(一個字節)所能表示的最大范圍(-128~127)。這好比某人在賓館定了一個單人間(聲明byte類型變量),等入住的時候,說自己太胖了,要住雙人間,這時賓館服務員(編譯器)是不會答應的。解決的辦法很簡單,需要重新在一開始就定雙人間(重新聲明age2為short類型)。
⑵ 在定義變量后,對變量賦值時,運算符(=)左右兩邊的類型要一致。例如,在本例第5行是錯誤的,因為在默認情況下,包含小數點的數(12.5)是雙精度double類型的,而“=”左邊定義的變量price是單精度float類型的,二者類型不匹配!這好比一個原本定了雙人間的顧客,非要去住單人間,刻板的賓館服務員(編譯器)一般也是不答應的,因為單人間可能放不下雙人間客人的那么多行李,丟了誰負責呢?如果住雙人間的顧客非要去住單人間,那需要雙人間的顧客顯式聲明,我確保我的行李在單人間可以放得下,或即使丟失點行李,我也是可以承受的(即強制類型轉換)。下面的兩個語句都是合法的。
float price=12.5f; //中規中矩的定義,一開始就保證“=”左右類型匹配 float price=(float)12.5; //一開始“=”右邊不匹配,通過強制類型轉換后,“=”左右類型匹配
3.2.7 認識運算符和表達式
計算機的英文為Computer,顧名思義,它存在的目的就是用來做計算(Compute)的。而要運算就要使用各種運算符。最簡單的算術運算符是加(“+”)、減(“-”、)、乘(“*”)、除(“/”)、取余(“%”)等。
表達式則是由操作數與運算符所組成,操作數可以是常量、變量,甚至可以是方法。下面的語句說明了這些概念的使用。
int result=1+2;
在這個語句中,1+2 為表達式,操作符為“+”,計算結果為 3,通過“=”賦值給整型變量result對于表達式,由于操作符是有優先級的,所以即使有計算相同的操作數和相同的操作符,其結果也是有可能不一樣的,例如:
c = a + b /100; //假設變量a,b,c為已定義的變量
在上述的表達式中,由于除法操作符“/”的優先級比加法操作符“+”高,所以c的值為b除以100后的值再加上a之和,這可能不是程序員的本意,如果希望是a+b之和一起除以100,那么就需要加上括號()來消除這種模糊性,如下所示:
c = (a + b) /100; // a+b之和除以100
3.2.8 認識類
Java程序是由類(class)所組成。類的概念在以后會詳細講解,讀者只要記住,類是一種用戶自定義的類型就可以了,所有的Java程序都是由類組成的。下面的程序片段即為定義類的典型范例。
public class Test //定義public類—Test { … }
程序定義了一個新的public類Test,這個類的原始程序的文件名稱應取名為Test.java。類Test的范圍由一對大括號所包含。public是Java的關鍵字,指的是對于該類的訪問方式為公有。
需要注意的是:由于Java程序是由類所組成,因此在一個完整的Java程序里,至少需要有一個類。在第1章中,我們曾提到,在Java程序的文件名不能隨意命名,必須和public類名稱一樣(大小寫也必須保存一致)。因此,在一個獨立的源碼程序里,只能有一個public類,卻可以有許多non-public(非公有)類。若是在一個Java程序中沒有一個類是public,那么對該Java程序的文件名就可以隨意命名了。
Java提供了一系列的訪問控制符來設置基于類(class)、變量(variable)、方法(method)及構造方法(constructor)等不同等級的訪問權限。Java的訪問權限主要有4類:默認模式(default)、private(私有)、public(公有)和protected(保護)。對類和接口概念的深度理解,讀者可分別參閱第9章和第13章,這里僅需讀者了解,在Java中有這么4種訪問控制方式即可。
3.2.9 輸入與輸出
在Java中,流(Stream)是一個重要的但初學者很容易困惑的概念。輸入/輸出(I/O)是指程序與外部設備或其他計算機進行交互的操作。幾乎所有的程序都具有輸入與輸出功能,如從鍵盤上讀取數據,向屏幕或文件輸出數據等。通過輸入和輸出操作可以從外界接收信息,或者把信息傳遞給外界。Java把這些輸入與輸出操作用流的模式來實現,通過統一的接口來表示,從而使程序設計更為簡單。
流(stream)的概念最早源于UNIX操作系統中管道(pipe)的概念。在UNIX中,管道是一條不間斷的字節流,用來實現進程或程序間的通信,或讀寫外圍設備、外部文件之間的信息交互等。一個流必須有起源端和目的端,它們可以是計算機內存的某部分區域,也可以是某個磁盤文件,甚至可以是Internet上的某個URL。
為了便于理解,讀者可以將Java中流想象成一種“數據流通的管道”,文件和程序之間一旦有了數據請求,二者之間就會建立某種形式的連接,從而形成了一個數據流。
就如在真正的管道中,可以傳輸不同形態的東西,既可以是水,也可以是天然氣。類似的, Java中的數據流也有不同的形式,既可以是基于二進制的字節流,也可以是基于某種編碼方式(如Unicode、UTF-8等)的字符流。
流的方向是重要的,根據流的方向,流可大致分為兩類:輸入流和輸出流。當程序需要讀取數據時,就會開啟一個通向數據源的管道,程序可從該管道中提取數據,這種模式下的流稱之為輸入流。類似地,如果程序想要輸出數據,也會建立一個通往輸出目的地管道,一旦建立后,程序就可以經由此管道輸出數據,這種模式的流稱之為輸出流。關于數據流,它們的輸入、輸出關系可用下圖來說明。

作為程序輸入數據源,其對象可以是鍵盤,也可以是某個文件或磁盤。作為程序輸出數據源,其對象可以是顯示器,也可以是某個文件或磁盤。為了方便一些頻繁的設備交互,Java語言系統預定了3個可以直接使用的流對象,它們分別是:
⑴ System.in(標準輸入),通常代表鍵盤輸入。
⑵ System.out(標準輸出):通常輸出到終端顯示器。
⑶ System.err(標準錯誤輸出):通常將錯誤信息輸出到終端顯示器。
System.in是個標準的輸入流(InputStream )對象,它主要是用來連接控制臺程序和鍵盤的輸入。目前System.in并不經常用到,這是因為Java命令行應用程序主要是通過命令行參數或配置文件來傳遞數據的,對于圖形用戶界面(GUI)程序,則主要是用圖形界面來接納用戶的鍵盤輸入。
System.out是打印輸出流(PrintStream)對象,主要向控制臺輸出數據,這個對象經常會被面向控制臺的程序使用到,它也常被程序員用作程序調試輸出的工具。
System.err也是打印輸出流(PrintStream)對象,除了其主要用于錯誤輸出之外,它和System.out沒有太大區別。有些應用程序(如Java程序員常用的Eclipse)用System.err以紅色字體來輸出錯誤信息。它可以看作一個專門用于輸出錯誤信息的System.out。
數據的輸入、輸出屬于I/O操作部分,Java把處理輸入/輸出相關的類放在java.io包中,這個包不屬于java.lang包,沒有被默認加載,所以如果需要使用與I/O相關的類和對象時,需要把java.io顯式的導入(import)到相應的程序中。下面用范例3-3來說明標準輸入和輸出的使用。
【范例3-3】 簡單的輸入、輸出流使用范例(StreamInTest3 3.java)。
01 //Syetem.in、Syetem.out、Syetem.err的使用范例 02 import java.io.*; //導入Java中支持I/O類的包 03 public class StreamInTest3_3 04 { 05 public static void main(String args[]) 06 { 07 String str; 08 //創建標準輸入流對象stdin來接收鍵盤System.in的輸入 09 InputStreamReader stdin=new InputStreamReader(System.in); 10 //以緩沖流模式來接收stdin 11 BufferedReader bufin=new BufferedReader(stdin); 12 //使用try和catch機制來處理輸入的異常 13 try{
14 System.out.print ("請輸入字符:"); 15 //用str字符串對象來接收鍵盤輸入的一行數據 16 str=bufin.readLine();18 17 System.out.println ("你輸入的字符為:"+str); 18 }catch(Exception e){ 19 //System.out.println("發生I/O錯誤!!!"); 20 System.err.println("發生I/O錯誤!!!"); 21 e.printStackTrace(); 22 } 23 } 24 }
【運行結果】
運行程序并保存,結果如下圖所示。

【代碼詳解】
程序第2行,如果要完全使用Java輸入、輸出流類模塊,就必須導入相應的包庫(java.io.*)支持。java.io.*中的字母“i”表示input(輸入),字母“o”表示output(輸出),“*”是代表任何含義的通配符,它表示輸入/輸出(io)下所有模塊。在Java中,“.”表示對象與組件之間的所有關系,為了方便起見,讀者可以直接用中文“的”來代替之。譬如:
import java.io.*;
我們可以直接讀成“導入java“的”io包庫下“的”所有模塊”。
程序的第9行表示創建標準輸入流對象stdin ,來接收鍵盤System.in的輸入。
程序的第11行表示以緩沖流模式來接收stdin。緩沖機制主要是為了處理應用程序和外設(輸入/輸出)之間速度不匹配的問題。
程序的第15和19行,使用的是標準輸出對象System.out,這在前面的范例中頻繁使用。
程序第20行用System.err對象輸出程序的錯誤信息。
其實程序20行的功能完全可以用被注釋掉的第19行代替,二者均可輸出程序的錯誤信息,二者在此處可通用,所不同的是,使用System.err代碼的可讀性更好一點,其中err表示error(錯誤)。System.err可以理解為專用于輸出錯誤信息的System.out特例。
程序的13行到22行,使用了Java的try-catch錯誤捕捉處理機制。正如“天有不測之風云”一樣,在Java程序設計過程中,程序員雖已盡量考慮全面以避免各種錯誤,但從軟件工程角度來看,在程序運行過程中還是不可避免的發生各種不可預測的異常情況,程序越大,此類情況越是明顯。對此,一個良好的程序需要有一定的容錯機制,即不能因為程序成員的某個潛在的設計缺陷或用戶可能的操作失誤(如輸入信息出錯),而導致整個程序崩潰。因此,需要添加相應的代碼來處理程序中異常(Exception)錯誤。try-catch機制對于程序的健壯性(Robust)非常重要,我們會在第19章講到這方面的知識,這里讀者只需有個感性認識即可。
3.3 程序的檢測
本節視頻教學錄像:6分鐘
學習到本節,相信讀者大概可以依照前面的例子“照貓畫虎”,寫出幾個類似的程序了。而在編寫程序時,不可避免的會遇到各種編譯時(語法上的)或運行時(邏輯上的)的錯誤,接下來我們做一些小檢測,看看讀者能否準確地找出下面的程序中存在的錯誤。
3.3.1 語法錯誤
通過下面的范例應學會怎樣找出程序中的語法錯誤。
【范例3-4】 找出下面程序中的語法錯誤(代碼TestJava3 4.java)。
01 //下面程序的錯誤屬于語法錯誤,在編譯的時候會自動檢測到 02 public class TestJava3_4 03 { 04 public static void main(String args[]) 05 { 06 int num1=2;//聲明整數變量num1,并賦值為2 07 int num2=3;聲明整數變量num2,并賦值為3 08 09 System.out.println("我有"+num1"本書!"); 10 System.out.println("你有"+num2+"本書!") 11 ) 12 }
【范例分析】
程序TestJava3_4在語法上犯了幾個錯誤,若是通過編譯器編譯,便可以把這些錯誤找出來。事實上,在Eclipse中,語法錯誤的部分都會顯示紅色的下劃線,對應的行號處會有紅色小×。
首先,可以看到第4行,main() 方法的主體以左大括號開始,應以右大括號結束。所有括號的出現都是成雙成對的,因此第11行main() 方法主體結束時應以右大括號做結尾,而TestJava2_4中卻以右括號“)”結束。
注釋的符號為“//”,但是在第7行的注釋中,沒有加上“//”。在第9行,字符串的連接中少了一個“+”號。最后,還可以看到在第10行的語句結束時,少了分號“;”作為結束。
上述的3個錯誤均屬于語法錯誤。當編譯程序發現程序語法有錯誤時,會把這些錯誤的位置指出來,并告訴程序設計者錯誤的類型,程序設計者可根據編譯程序所給予的信息加以更正。比如,在沒有糾正第7行的錯誤時,編譯器會顯示下圖所示的錯誤信息。

將程序第7行的錯誤更改后,重新編譯,若還是有錯誤,再依照上述的方法重復測試,這些錯誤就會被一一改正,直到沒有錯誤為止。糾正上述錯誤后,保存并運行程序,正確的運行結果如下圖所示。

3.3.2 語義錯誤
若程序本身的語法都沒有錯誤,但是運行后的結果卻不符合程序設計者的要求,此時可能犯了語義錯誤,也就是程序邏輯上的錯誤。讀者會發現,想要找出語義錯誤比找出語法錯誤更加困難。因為人都是有思維盲點的,如果在編寫程序時,一旦陷入某個錯誤的思維當中,有時很難跳出來。排除一個邏輯上的語義錯誤,糟糕時可能需要經歷一兩天,才突然“頓悟”錯誤在哪里。
舉例來說,想在程序中聲明一個可以存放整數的變量,這個變量的名稱為num。在程序中即可寫出如下所示的語句。
【范例3-5】 程序語義錯誤的檢測(TestJava3 5.java)。
01 //下面這段程序原本是要計算一共有多少本書,但是由于錯把加號寫成了減號, //所以造成了輸出結果不正確,這屬于語義錯誤 02 public class TestJava3_5 03 { 04 public static void main(String args[]) 05 { 06 int num1=4; //聲明一整型變量num1 07 int num2=5; //聲明一整型變量num2 08 09 System.out.println("我有"+num1+"本書!"); 10 System.out.println("你有"+num2+"本書!"); 11 //輸出num1-num2的值s 12 System.out.println("我們一共有"+(num1-num2)+"本書!"); 13 } 14 }
【范例分析】
可以發現,在程序編譯過程中并沒有發現錯誤,但是運行后的結果卻不正確,這種錯誤就是語義錯誤。在第12行中,因失誤將“num1+num2”寫成了“num1-num2”,雖然語法是正確的,但是卻不符合程序設計的要求,只要將錯誤更正后,程序的運行結果就是想要的了。
【運行結果】
保存并運行程序,結果如下圖(左)所示,顯然不符合設計的要求。在糾正12行的語義錯誤之后的輸出結果如下圖(右)所示。


范例3-5的輸出結果圖
糾正語義錯誤的輸出結果
3.4 提高程序的可讀性
本節視頻教學錄像:3分鐘
能夠寫出一個功能正確的程序,的確很讓人興奮。但如果這個程序除了本人之外,其他人都很難讀懂,那這就不算是一個好的程序。所以程序的設計者在設計程序的時候,除了完成程序必需的功能,也要學習程序設計的規范格式。除了前面所說的加上注釋之外,還應當保持適當的縮進,保證程序的邏輯層次清楚。我們前面的范例程序都是按縮進的方法來編寫的,“美的東西都是丑的東西襯托出來的”。讀者可以比較下面的兩個范例,相信看完之后,就會明白程序中使用縮進的好處了。
【范例3-6】 縮進格式的程序(TestJava3 6.java)。
01 //以下這段程序是有縮進的樣例,可以發現這樣的程序看起來比較清楚 02 public class TestJava3_6 03 { 04 public static void main(String args[]) 05 { 06 int x; 07 08 for(x=1;x<=3;x++) 09 { 10 System.out.print("x="+x+","); 11 System.out.println("x*x="+(x*x)); 12 }
13 } 14 }
【運行結果】
保存并運行程序,范例3-6結果如下圖所示。

【范例3-7】 非縮進格式的程序(代碼TestJava3 7)。
01 //下面的程序與前面程序的輸出結果是一樣的,但不同的是, 02 //這個程序沒有采用任何縮進,代碼閱讀者看起來很累,代碼邏輯關系不明顯,不易排錯 03 public class TestJava3_7{ 04 public static void main(String args[]){ 05 int x;for(x=1;x<=3;x++){ 06 System.out.print("x="+x+","); 07 System.out.println("x*x="+(x*x));}}}
【范例分析】
TestJava3_7這個例子雖然簡短,而且也沒有語法錯誤,但是因為編寫風格(Programming Style)的關系,閱讀起來肯定沒有TestJava3_6這個程序好讀,所以建議讀者盡量使用縮進,養成良好的編程習慣。良好代碼編寫風格是優秀程序員需要達到的境界,在滿足程序基本的功能和性能目標前提下,還要滿足代碼的“雅致”之美。良好編程風格可增強代碼的可讀性、可移植性,更加有利于團隊合作(teamwork)。只有程序設計者自己能明白的代碼注定是“孤單的”。
3.5 高手點撥
本節視頻教學錄像:5分鐘
注意Java源代碼中的字符半角和全角之分
Java繼承了C/C++的很多語法,其中一個語法就是每個語句(Statement)后加一個分號“;”作為本語句的結束。這本是一個很簡單的語法要求,但是對于東方國家的初學者來說,卻是一個極容易犯錯的問題。其主要原因在于混淆了半角“;”和全角“;”的區別。那么什么是字符的半角和全角呢?
傳統上,在西歐語系使用的計算機系統中,每一個字母或符號使用1個字節的空間,而1個字節由8比特(bit)組成,因此共有28=256個編碼空間,這對西歐語系的字符足夠用了;但是對于漢語、日語及韓語文字,由于其數量遠遠超過256個,故慣常使用兩字節來儲存一個字符,為了使字體看起來齊整,英文字母、數字及其他符號,也由原來只占1個字空間,改為用2個字的空間來顯示,并用2個字節來儲存。所以,中、日、韓等文字沒有半角之說,統一為全角字符。相比起來,英文字母、數字及其他西歐符號用1個字節表示就是半角,用2個字節表示就是全角,如下圖所示。

Java的初學者,在使用中文輸入法輸入英文字符時,很容易在中文輸入模式輸入全角的分號“;”、左右花括號“{”、“}”、左右括號“(”、“)”及逗號“,”,而Java的編譯器在語法識別上僅僅識別這些字符對應的半角。因此建議初學者在輸入Java語句(不包括注釋和字符串的內容)時,在中文輸入模式下,要么按“Ctrl+Shift”組合鍵切換至英文模式,要么將中文輸入法轉變為半角模式,如下圖所示,中文輸入法中的“太陽”標記為全角模式,單擊該圖標可以切換為“月亮”標記——半角模式。


3.6 實戰練習
本節視頻教學錄像:10分鐘
1.分析下面程序代碼的運行結果,運行程序并查看實際結果,分析產生結果的原因。
01 public class Exercise3-1 02 { 03 public static void main(String args[]) 04 { 05 int x=10; 06 int y=3; 07 System.out.println(x/y); 08 } 09 }
2. 用float型定義變量:float f = 3.14; 是否正確? (Java面試題)
解析:不正確。賦值運算符(=)左右兩邊的精度類型不匹配。在默認情況下,包含小數點的實數,如本題中的3.14,被存儲為double類型(即雙精度),而float類型定義的變量,如本題中的f,是單精度的。如果想讓上面的語句編譯正確,應該對賦值運算符(=)右邊的值做強制類型轉換,即把常量3.14強制轉換為單精度(即float類型),如下所示:
float f=(float)3.14; //正確
或者,一開始就把3.14存儲為單精度類型,在3.14后加上小寫字母‘f’或大寫字母‘F’,如下所示:
float f=3.14f; //正確 float f=3.14F; //正確