134
本本本本 本本本本本本本 本本本本本本本本本本本本本本本本本本本本本本本本本本本 本本本本本 本本本 本本本本本本本本本本本 本本本本 本本本 本本本本本本本 本本 ()(),,、、( 本本本本本本本本本本本本本本本 80% 本本本本本本本本本本本本本本本 本本本本本本本本本本本本本本本本 本本本本本本本本本本本本本本本本本本 本本本本本本本本本 ),,、; 本本本本 本本本本本本本本本本本本本本本本 本本本本本本本本本本本本本本本本本本本本本本本本本本本本 ,,。 本本本本本 © 本本本本本本本本本本 Java 本本本本本 本 17 本

SCJP ch17

Embed Size (px)

Citation preview

Page 1: SCJP ch17

本投影片(下稱教用資源)僅授權給採用教用資源相關之旗標書籍為教科書之授課老師(下稱老師)專用,老師為教學使用之目的,得摘錄、編輯、重製教用資源(但使用量不得超過各該教用資源內容之 80% )以製作為輔助教學之教學投影片,並於授課時搭配旗標書籍公開播放,但不得為網際網路公開傳輸之遠距教學、網路教學等之使用;除此之外,老師不得再授權予任何第三人使用,並不得將依此授權所製作之教學投影片之相關著作物移作他用。

著作權所有 © 旗標出版股份有限公司

Java 標準類別庫第 17 章

Page 2: SCJP ch17

2

學習目標

認識 Java 語言的標準類別庫 學習使用內建的數學運算方法 熟悉基本資料類別 學習 Math 、 Date 、 Calendar 類別的相關應用 學習日期、數值、貨幣的格式化方法 學習搜尋字串與分解字串的技巧

Page 3: SCJP ch17

3

前言

前幾章我們開始接觸到 Java 平台提供的各種 『功能』 , 像是執行緒、例外處理、串流類別等。

這些『功能』都是內建在 Java 標準類別庫 (Stand

ard Class Library) 中 , 或是稱為 Java API (Applicat

ion Programming Interfaces, 應用程式介面 ) , 只要在程式中使用這些現成的類別及方法 , 就可進行複雜的工作 , 例如用 BufferedReader 以緩衝方式讀取檔案或鍵盤輸入。

本章將介紹更多實用的 Java API, 方便您撰寫各式各樣的 Java 程式 , 利用程式來解決各式各樣的問題。

Page 4: SCJP ch17

4

17-1 甚麼是 Java 標準類別庫?

到目前為止 , 我們已學到的 , 大多屬於『 Java 程式語言』的部份 , 包括變數、運算式、流程控制等基本語法要素 , 以及物件導向的語法:類別、繼承等等。

不過如同第 1 章所介紹的 , Java 語言要發揮功能必須有個可供 Java 程式執行的 Java Platform (Java

平台 ) 環境。 Java Platform 包含兩大部份:

▪ JVM

▪ Java API

Page 5: SCJP ch17

5

甚麼是 Java 標準類別庫? JVM 提供一個讓 Java bytecode 程式執行的環境 , 而

Java API 則是一套內含相當多類別、介面定義的集合 , 同版本 Java Platform 所提供的 Java API 種類、數量都相同 , 所以我們可稱之為 Java 標準類別庫 (Standard Class Library) 。

就好像我們可以從大賣場的倉庫中找到許多不同用途的百貨用品、食品 , 我們也能從 Java 標準類別庫這個 Java 程式設計人員專用的倉庫中 , 找到各式各樣的類別來使用 , 讓程式發揮不一樣的功能。

Java 標準類別庫中的類別 , 已依其屬性適當分成多種不同的套件 , 以 JavaSE (Standard Edition) 這個 Java Platform 為例 , 其 Java API 部份提供了如下圖所示的多種套件。

Page 6: SCJP ch17

6

甚麼是 Java 標準類別庫?

Page 7: SCJP ch17

7

甚麼是 Java 標準類別庫?

每個套件名稱也都暗示了其功能及用途 , 像是前一章介紹的 java.io 套件就是有關輸入與輸出的類別集合;而圖中的 Security 所指的 java.security 套件 , 則是與安全性有關的類別集合。

在眾多的套件中 , 有關圖形使用者介面及繪圖的幾個套件 , 例如上圖有一列包括 AWT 、 Swing 、 Java

2D , 這三項合稱為 Java Foundation Classes (簡稱JFC), 在附錄 A 就會介紹這部份套件的用法。

Page 8: SCJP ch17

8

甚麼是 Java 標準類別庫?

如圖示 , Java API 的內容相當多 , 也不是一本入門書可介紹完的 , 因此本書只能做重點式的介紹。前一章我們介紹過 java.io 套件中的輸出入類別和介面 ,

本章則要介紹以下 3 個套件中一些實用的類別:▪ java.lang :顧名思義 , 此套件包含了 Java 語言最基本的核心類別 , 其中包括我們已學過的字串、執行緒、及例外類別 , 都屬於此套件。而本章要介紹的則是可讓我們處理數字的 Math 類別 ,

以及可用來包裝基本資料型別的『基本資料類別』。

Page 9: SCJP ch17

9

甚麼是 Java 標準類別庫?

▪ java.util :這個套件有如 Java 程式設計的萬用工具箱 , 提供了開發各種程式都可能會用到的輔助性類別。例如處理日期的 Date 、 Calendar 類別 , 設定國別語系的 Locale 類別 , 搜尋與分解字串的 regex.Patt

ern 、 regex.Matcher 、及 Scanner 類別等。

▪ java.text :提供將資料格式化的類別 , 例如 DateFor

mat 可進行日期的格式化 , 以及 NumberFormat 可進行數值與貨幣的格式化。

Page 10: SCJP ch17

10

查看 Java API 文件

當然在整個 Java API 中還有很多功能強大且實用的類別 , 也許您會發現有某個套件對解決您的問題更有幫助。

但限於本書篇幅 , 我們無法一一介紹所有的類別 , 若您想認識一下 Java API 中到底有哪些套件、類別可使用 , 建議直接連上昇陽公司的 Java 線上文件網站 (http://java.sun.com/javase/6/docs/) 一探究竟。

Page 11: SCJP ch17

11

查看 Java API 文件

Page 12: SCJP ch17

12

查看 Java API 文件

Page 13: SCJP ch17

13

查看 Java API 文件

Page 14: SCJP ch17

14

查看 Java API 文件

▪ 您也可先在左上框中點選要查閱的套件 , 則左下框即會篩選出該套件中的所有類別 , 以供您點選查閱。

Page 15: SCJP ch17

15

17-2 基本資料類別

第 11 章提過 , java.lang 中有一組特別的類別 , 是專用於以物件的方式包裝 Java 基本資料型別 , 所以可稱之為基本資料類別 (Primitive wrapper class)

或包裝類別 (Wrapper class) 。 為什麼要用物件的方式包裝基本型別呢? 因為在某些狀況下 , 您要處理的雖然是整數、浮點數等資料型別 , 但要利用的工具卻只接受物件形式的資料 , 此時就要先將基本資料型別包裝成物件再來進行處理 , 在下 一 章要介紹的 Java Collection 就是這類『工具』的代表性範例。

Page 16: SCJP ch17

16

基本資料類別 此外這些類別也提供許多實用的 static 方法 , 讓我們方便進行資料格式的轉換 , 例如我們每次從鍵盤取得輸入的字串 , 就會呼叫這些方法將字串轉換成所需的格式 ( 像是 Integer.parseInt() 方法 ) 。

本節我們先來進一步認識這些包裝類別 , 每個基本資料型別都有其對應的包裝類別 , 如下:

Page 17: SCJP ch17

17

基本資料類別

除了 Boolean 、 Character 外 , 其它幾個類別都是 Number 這個抽象類別的子類別。

而且這幾個用來存放數值的類別 , 都有提供一組相似的方法 ( 例如常用的 parseInt() 、 parseDouble()

等 ) 。 基本資料類別有個重要的特性不可不知:包裝成物件的數值或字元等 , 其值是無法改變的。

一方面是這些類別都沒有提供修改物件內含值的方法;再者基本資料類別都是 final 類別 , 所以我們也不能從其衍生可更改數值的新類別。

Page 18: SCJP ch17

18

基本資料類別

這樣的設計其實是可以理解的 , 畢竟使用基本資料型別的變數已非常方便 , 平常不需多費一道工夫將它們包裝成物件來用。

以下我們就先來看如何建立包裝類別的物件及取出物件中的資料。

Page 19: SCJP ch17

19

17-2-1 建立基本資料類別物件

建構方法 取得物件的值 基本資料類別的常數

Page 20: SCJP ch17

20

建構方法

建立基本資料類別的物件 , 相當於將基本型別的變數值裝到物件中。

建立的方法很簡單 , 就是直接以 new 呼叫類別的建構方法 , 例如建立一個 Boolean 物件可用如下的程式:

Page 21: SCJP ch17

21

建構方法

關於各類別的建構方法簡單整理如下:▪ Character 類別的建構方法只接受字元型別的參數。

▪ Boolean 、 Byte 、 Double 、 Integer 、 Long 、 Shor

t 類別的建構方法 , 只接受其對應型別的變數、字面常數或字串為參數。例如上述的例子中 , 就用布林變數和字串建立 Boolean 類別的物件。下面是 Short

的範例:

Page 22: SCJP ch17

22

建構方法

▪ Float 除了能用 float 型別和字串為建構方法的參數 ,

也能直接用 double 型別的變數當參數呼叫建構方法 ,

不需自行將參數做強制型別轉換。

Page 23: SCJP ch17

23

取得物件的值

當我們將基本資料型別包裝成物件後 , 可透過類別所提供的多種方法 , 將其值取出使用。

這些類別至少都提供一種 xxxValue() 方法可傳回物件的值 , 其中 xxx 需代換為基本資料型別的名稱 ,

例如 Boolean 物件可使用 booleanValue() 方法、Character 物件可使用 charValue() 方法。

Page 24: SCJP ch17

24

取得物件的值

至於各 Number 類別的子類別就較具彈性 , 它們的物件可呼叫下列傳回數值型別的方法 , 因為這些方法都是繼承自 Number 抽象類別 , 這些方法包括:

Page 25: SCJP ch17

25

取得物件的值

使用上列方法時要注意 , 對範圍較大的物件 ( 例如 Double), 取其較小範圍的基本資料型別 (byte), 就可能發生無法表示的情形 , 請參考以下範例程式:

Page 26: SCJP ch17

26

取得物件的值

Page 27: SCJP ch17

27

取得物件的值

Page 28: SCJP ch17

28

取得物件的值

1. 第 7 、 8 行分別建立 Integer 、 Double 類別物件。

2. 第 11 、 14 行分別以基本資料類別的物件為參數 ,

呼叫自訂的 showall() 方法進行示範。3. 第 17〜 25 行自訂的 showall() 方法 , 只是單純呼叫各類別的 xxxValue() 方法並輸出結果。此方法宣告的參數為 Number 類別的物件 , 所以程式中可用 Integer 、 Double 類別的物件為參數呼叫之。

Page 29: SCJP ch17

29

取得物件的值

如執行結果所示 , 當物件的數值超出取值方法傳回的基本資料型別所能表示的範圍時 , 經常會出現不可預期的結果。

例如上例中的 123456789 轉成 byte 和 short 時分別變成 21 、 -13035, 而轉成 float 型別時 , 也產生一點誤差變成 1.23456792E8 ( 相當於 123456792) 。

至於倒數第 4 個輸出的 Infinity, 則是 Java 特別定義的常數 , 代表無限大的意思 (因為 5.376543e200

遠超過 float 可表示的範圍 ) , 以下就來認識基本資料類別中所定義的常數值。

Page 30: SCJP ch17

30

基本資料類別的常數

除了 Boolean 類別外 , 其它幾個基本資料類別都有定義至少 3 個 static 變數 , 用以表示一些常數值。

其中最普通的一類常數 , 就是表示各基本資料型別的數值範圍 ( 可表示的最大值及最小值 ) , 以及各型別的大小 ( 所佔的位元數 ) 。

各型別的這 3 個常數值如下表所示。

Page 31: SCJP ch17

31

基本資料類別的常數

Page 32: SCJP ch17

32

基本資料類別的常數

除此之外 , 浮點數的 Float 、 Double 類別 , 分別各有 3 個代表極限值及非數值 (Not-a-Number, NaN)

等特殊值的 static 變數:

Page 33: SCJP ch17

33

17-2-2 基本資料類別與字串

認識基本資料類別物件的建立及取值方式後 , 我們再多介紹一些與字串相關的方法。

這些方法大概可分為幾類:▪ 從字串建立類別物件:此類方法和前面介紹的建構方法有點像 , 可將一字串轉成數值型的類別物件。但建構方法的字串只能用十進位表示 , 而以下要介紹的方法不但可接受以不同數字系統表示的字串 , 而且是屬於 static 方法。

▪ 從類別物件產生字串:各資料類別物件都可呼叫特定方法將其值轉成字串表示。

Page 34: SCJP ch17

34

基本資料類別與字串

▪ 將基本資料型別轉成字串:這類是各類別提供的 stati

c 方法 , 可用來將各基本資料型別轉成字串表示。

▪ 將字串轉成基本資料型別:同樣是 static 方法 , 而且我們已用過多次 , 每次由鍵盤取得輸入時的用的 Inte

ger.parseInt() 、 Double.parseDouble() 就屬此類。

Page 35: SCJP ch17

35

從字串建立類別物件

除了 Character 類別外 , 各基本資料類別至少都提供一個 static 的 valueOf() 方法 , 只要以適當格式的字串呼叫之 , 即可傳回該類別的物件。例如:

Page 36: SCJP ch17

36

從字串建立類別物件

整數型類別除了有類似上列的 valueOf() 方法 , 還有個多重定義的版本可指定此字串所採的數字系統:

以上僅列 Integer 類別的 valueOf() 方法 , 其它 B

yte 、 Short 、 Long 也都有這個方法可用 , 但它們的傳回值都是該類別所對應的型別 , 請參考下列程式。

Page 37: SCJP ch17

37

從字串建立類別物件

Page 38: SCJP ch17

38

從字串建立類別物件

Page 39: SCJP ch17

39

從字串建立類別物件

1. 第 7〜 10 行宣告 4 個以不同數字系統表示的數字字串。

2. 第 12〜 15 行分別呼叫各整數型類別的 valueOf

() 方法將字串轉換成數字物件 , 並輸出結果。 使用 valueOf() 方法時要特別注意:如果字串內容

不符合數字格式、或是數字超出物件可表示的範圍 ( 例如在上列程式中將 str16 轉成 Byte 物件 ), 都會引發 NumberFormatException 例外。

Page 40: SCJP ch17

40

將類別物件、資料型別轉成字串

在第 11 章已提過所有基本資料類別都有實作各自的 toString() 方法 , 可將物件轉換成字串表示 , 所以我們能在 print() 、 println() 方法中直接將之輸出 ,

或者轉成字串來處理。 除了將物件轉成字串外 , 各數值型的類別也都支援以類別名稱來呼叫 toString() 的方法 , 可將其對應的基本資料型別變數轉換成字串。

Page 41: SCJP ch17

41

將類別物件、資料型別轉成字串

但各類別的 toString() 方法都只能將數值轉成 10

進位制的字串表示 , 若想轉成 2 進位、 8 進位、 1

6 進位、甚至於其它數字系統等方式來表示 , 則需使用只有 Integer 、 Long 類別才提供的下列方法:

Page 42: SCJP ch17

42

將類別物件、資料型別轉成字串

此處所列為 Integer 類別的方法 , Long 類別也有一組同名的方法 , 只不過它們接受的參數型別為 long 。

以下就是使用這些方法將整數轉成不同進位表示的字串範例:

Page 43: SCJP ch17

43

將類別物件、資料型別轉成字串

Page 44: SCJP ch17

44

將類別物件、資料型別轉成字串

1. 第 7 、 8 行分別宣告 int 、 long 型別的變數 , 以供程式轉成字串。

2. 第 10〜 13 行分別呼叫各 toXxxString() 方法將字串轉換成數字物件 , 並輸出結果。

Page 45: SCJP ch17

45

將字串轉成基本資料型別

基本資料類別也提供多個方法 , 可將字串轉成基本資料型別。

其中有一類方法 , 就是每次從鍵盤取得輸入時 , 用來將字串轉成基本資料型別的 Integer.parseInt() 、 Do

uble.parseDouble() 等方法。 這幾個基本的 parseXxx() 方法我們都已用過多次 ,

就不再多介紹。

Page 46: SCJP ch17

46

將字串轉成基本資料型別

比較特別的是 , 整數型的類別所提供的 parseXxx()

方法 , 也有另一種形式 , 可加上待轉換字串是用哪一種數字系統的參數 , 如此就能將不同進位表示的字串轉成基本資料型別:

Page 47: SCJP ch17

47

將字串轉成基本資料型別

我們直接來看以下的應用實例:

Page 48: SCJP ch17

48

將字串轉成基本資料型別

Page 49: SCJP ch17

49

將字串轉成基本資料型別

Page 50: SCJP ch17

50

將字串轉成基本資料型別

Page 51: SCJP ch17

51

將字串轉成基本資料型別

1.第 12 〜 35 行以迴圈的方式讓程式會一直循環請使用者輸入數字 , 並進行轉換。

2.第 18〜 29 行的 try 段落主要是預防第 19 、 27

行轉換數字時發生格式錯誤的例外。3.第 21 行用 if 判斷使用者是否輸入 0, 是就跳出迴圈 , 結束程式。

4.第 30〜 34 行的 catch 區塊會捕捉 NumberFor

matException 例外 , 並輸出一段訊息。 catch 區塊結束後 , 仍會重新執行迴圈。

Page 52: SCJP ch17

52

將字串轉成基本資料型別

Character 類別也有一個類似的方法 , 可將字元轉成數字:

例如 Character.digit('A', 16) 會傳回 10( 在 16 進位中 , A 代表 10 進位的 10) 。

但 digit() 方法並不會在第一個參數超出範圍時拋出例外 , 而是會傳回 -1, 例如 Character.digit('A', 8)

就會傳回 -1 。

Page 53: SCJP ch17

53

將字串轉成基本資料型別

另外還有個類似的方法則是:

這個方法是將英文字母接續在數字 0〜 9 後面排列 ( 不分大小寫 ), 例如:

除了英文字母外 , Unicode 中定義的羅馬數字也會傳回代表的數值 , 例如:

Page 54: SCJP ch17

54

17-2-3 基本資料類別所提供的其它方法

除了上述各種轉換方法外 , 基本資料類別也提供一些簡單實用的『工具』方法 , 可讓我們對物件的值做其它處理。

Page 55: SCJP ch17

55

字元的判斷與轉換方法

前述介紹的多種方法 , Character 類別大多並未提供 ,

不外是因為單一字元與數字 / 字串間的轉換的實用性並不大。

但 Character 類別其實有提供相當多的 static 方法 ,

可做字元的判斷和轉換。

Page 56: SCJP ch17

56

字元的判斷與轉換方法 首先介紹一些判斷字元的方法 , 也就是判斷字元是不是屬於某一特別的類別 , 例如:

這些方法的傳回值都是 boolean 型別 , 是該類字元就傳回 "true" 、不是就傳回 "false" 。關於空白字元要說明一下 , 舉凡空白、 '\t' 、 '\n' 等都算是空白字元。

Page 57: SCJP ch17

57

字元的判斷與轉換方法

以下是個利用字元方法的簡單範例:

Page 58: SCJP ch17

58

字元的判斷與轉換方法

Page 59: SCJP ch17

59

字元的判斷與轉換方法

由執行結果可發現:▪ 不論中英文 , 每個字 (母 ) 都視為一個字元。▪ 即使按了多下 [Tab] 鍵產生很寬的空白 , 每個 [Tab] 鍵仍只計為 1 個空白字元 , 所以程式會計算為 "6 個空白字元 " 。

▪ 程式並未計算標點符號 , 所以輸入的標點符號都會被忽略。

Page 60: SCJP ch17

60

字元的判斷與轉換方法

至於轉換字元的方法則有下面 2 個:

這 2 個方法都會傳回轉換後的字元 , 如果參數 ch

不是有大小寫分別的字元 , 就傳回原來的字元。因此像下列敘述也不保證會傳回 true :

Page 61: SCJP ch17

61

比較的方法

要做基本資料類別物件間的比較 , 若只是看兩者是否相等 , 可使用第 11 章介紹的繼承自 java.lang.Obj

ect 的 equals() 方法。 若要比較誰大誰小的話 , 可使用除了 Boolean 類別以外 , 其它類別都提供的 compareTo() 方法:

Page 62: SCJP ch17

62

比較的方法 以上為簡化表示 , 所以將參數型別寫成 "Object" , 實際上各類別的 compareTo() 方法都只能比較同類別的物件。

若參數物件是不同類別 , 則會引發 ClassCastException 例外。▪ 注意 , == 是用來比較是否為同一個物件 , 而 equals() 是用來比較物件的意義 ( 內含值 ) 是否相等 , 請不要混為一談。此外 , 當包裝物件與基本型別資料進行 == 比較時 , 包裝物件會先轉換成基本型別資料 , 因此會針對其內含值做比較 , 而非比較是否為同一物件。

▪ 包裝類別的變數也有可能是 null 參照 , 例如『 Integer i; 』 , 則因 i 未參照到實體 , 所以其值為 null, 而非 0 。SCJP 考題中有時會以此做為陷阱。

Page 63: SCJP ch17

63

17-3 Math 類別

在前面幾章 , 我們就曾使用過 java.lang 套件中的 Math 類別所提供的功能 , Math 類別提供了一組方便我們進行各種數學運算的方法。

我們可做如下的比喻: Java 的加減乘除運算子提供了普通計算機的計算功能 , 而 Math 類別則提供了『工程型』計算機的計算功能。

Page 64: SCJP ch17

64

Math 類別

Math 類別除了提供多種計算方法外 , 還定義了兩個 static 常數:

因此在程式中可直接用這兩個常數進行相關計算。以下就來分類介紹 Math 類別中的各種方法。

Page 65: SCJP ch17

65

17-3-1 比較方法

我們要介紹的第一組 Math 類別的方法是簡單的比較方法。

這些方法會比較兩數字 , 並傳回其中的最大值 (max

() 方法 ) 或最小值 (min() 方法 ) 。 雖然像這樣的運算 , 我們也能用簡單的 if/else 或以比較運算字 (?:) 來做;但在寫程式時 , 使用 Math

提供的方法 , 仍不失為一種簡單而快速的方案。

Page 66: SCJP ch17

66

比較方法

這兩個方法各有下列 4 種 , 以用於不同的參數類型:

Page 67: SCJP ch17

67

比較方法

其實 Math 類別本身也是用比較運算子 ?: 來設計上列傳回較大值或較小值的方法 , 不過當程式的敘述較為複雜時 , 直接用 Math 類別提供的方法 , 會比我們自己在程式敘述中用 ?: 運算字 , 更容易閱讀及瞭解。

上述方法的用法可參考以下範例。

Page 68: SCJP ch17

68

比較方法

Page 69: SCJP ch17

69

17-3-2 求絕對值與近似值

除了 min() 、 max() 外 , 另一組 Math 類別提供的簡單方法就是求絕對值與近似值。

這些 static 方法如下所示:

Page 70: SCJP ch17

70

求絕對值與近似值

初學程式設計者可能對 ceil() 與 floor() 方法不太熟悉 , 其實它們的意義很簡單: ceil 是天花板的意思 , 所以 ceil() 傳回的是大於或等於參數值的最小整數;而 floor 則是地板 , 所以 floor() 會傳回小於或等於參數值的最大整數。

至於 rint() 、 round() 的計算方式雖然不太相同 , 但多數情況下其計算結果都相同 , 只是傳回值的型態不同。

這幾個方法的應用方式 , 請參見以下範例。

Page 71: SCJP ch17

71

求絕對值與近似值

Page 72: SCJP ch17

72

求絕對值與近似值

Page 73: SCJP ch17

73

求絕對值與近似值

在此要補充說明上述方法的一些特別狀況:▪ 呼叫 Math.ceil() 時的參數值若小於 0 、大於 -1,

則傳回值會是 -0.0 。

▪ 呼叫 Math.round() 時的參數值若小於 Integer.MIN_

VALUE, 則傳回值為 Integer.MIN_VALUE ;若大於 I n teger.MAX_VALUE, 傳回值會是 Integer.MAX_V

ALUE 。

▪ 同理 , 呼叫 Math.round() 時的參數若小於 Long.MI

N_VALUE 或大於 Long.MAX_VALUE, 則分別傳回為 Long.MIN_VALUE 或 Long.MAX_VALUE 。

Page 74: SCJP ch17

74

17-3-3 基本數學計算方法

介紹了 Math 類別中一些簡單的方法後 , 接下來要開始介紹進行較複雜運算的方法。

首先來看幾個基本的計算功能:

Page 75: SCJP ch17

75

基本數學計算方法

pow() 、 sqr t ( ) 、 cbr t ( ) 方法的用法都很簡單 ,

應不必再加說明。 至於 exp() 、 log() 方法雖然一般人不太會用到 , 但在微積分的領域則是很常看到 , 舉凡數學、物理、金融、財務等各種領域 , 都會看到用到自然對數的計算式 , 在此我們就不深入探討。

以下就是一個使用 pow() 來計算定期存款本利和的範例。

Page 76: SCJP ch17

76

基本數學計算方法

Page 77: SCJP ch17

77

基本數學計算方法

Page 78: SCJP ch17

78

基本數學計算方法

1. 在第 12 〜 18 行分別取得利率、及存款年數。2. 第 24 行用 Math.pow() 方法來計算複利計算時的

本利和。算出來的結果 , 再用前一章介紹的格式化輸出方式 , 以 printf() 方法及 "%.1f" ( 只顯示小數後 1 位 ) 的方式輸出。

Page 79: SCJP ch17

79

17-3-4 產生亂數方法

所謂亂數就是一個由電腦隨機產生的數字 , 就像請大家隨便想一個數字寫下來 , 每次想的都可能不同、各數字彼此間也沒什麼關聯性 , 就叫亂數。

在撰寫某些應用程式時就很需要用到亂數方法 , 最普遍的例子就是遊戲程式 , 例如射擊遊戲中的射擊目標每次出現的位置、行動方向都要不同 , 這時就需利用亂數產生器來產生一個隨機數字 , 以決定射擊目標的出現位置、行動方向等性質。

Page 80: SCJP ch17

80

產生亂數方法

Math 類別的 random() 方法就是個會傳回『亂數』的方法 , 它會隨機傳回大於等於 0 、小於 1 之間的倍精度浮點數 , 讓程式取得必要的亂數進行相關計算。▪ 其實電腦只是個機器 , 它並不像人真的可以隨便亂想一個數字出來 , 所以 random() 其實是用特定的演算法產生『 不規則』 的數字 , 並非真的亂數 , 因此也稱之為『虛擬』 亂數 (pseudo random number) 。

以下的程式 , 就是用亂數方法來產生隨機樂透號碼的程式 , 由此範例便可瞭解如何利用 random() 來產生亂數。

Page 81: SCJP ch17

81

產生亂數方法

Page 82: SCJP ch17

82

產生亂數方法

Page 83: SCJP ch17

83

產生亂數方法

1. 第 11 、 12 行取得使用者輸入 , 決定要產生的號碼組數。

2. 第 14〜 34 行的迴圈就是在產生指定組數的號碼。3. 第 16〜 18 行建立一個整數陣列 lotto[], 並將 1〜 49 的數字依序填入其中。

Page 84: SCJP ch17

84

產生亂數方法

4. 第 21 〜 31 行的 do/while 迴圈進行產生 6 個隨機數字的動作。因為程式可能產生重複的號碼 ,

但這是不允許的 , 所以不確定迴圈會執行幾次 , 故以 do/while 迴圈來執行。

5. 第 22 行呼叫 Math.random() 方法產生 0 至 4

8 間的亂數。

Page 85: SCJP ch17

85

產生亂數方法

6. 第 24 〜 30 行的 if/else 是用來判斷產生的數字是否重複。每產生一新亂數時 , 就取出對應的 lotto

[] 陣列元素值 , 並將該元素值設為 0, 下次若又產生同一數字時 , 就會發現該元素值為 0, 因此就會執行第 28 行的 continue 敘述 , 重新執行迴圈產生另一個亂數。

7. 第 29 行每產生一個數字 , 就將 count 加 1, 當 31 行的 while 檢查 count 不小於 6, 表示已產生 6 個數字了 , 就不再執行迴圈。

Page 86: SCJP ch17

86

17-4 日期、數字、貨幣的應用與國際化

在程式中經常會使用到日期、時間資料 , 除了取得目前的日期、時間外 , 有時也會換算為星期幾、加減幾天、或減幾個月 . . . 等。

而在輸入或輸出各類日期、數字、貨幣資料時 , 又往往會因不同的國別、語系而有不同的格式。

這些在 Java API 中都有完善的支援 , 底下我們就一一介紹。

Page 87: SCJP ch17

87

17-4-1 Date 與 Calendar 類別的應用

java.util.Date 可用來儲存單一的日期與時間 , 而 ja

va.util.Calendar 則像是萬用月曆 , 可進行各種日期設定、轉換、加減等操作。

這二個類別的常用方法如下:

Page 88: SCJP ch17

88

Date 與 Calendar 類別的應用

Page 89: SCJP ch17

89

Date 與 Calendar 類別的應用

▪ 以上所指的欄位 , 可以是 YEAR 、 MONTH 、 DAY

_OF_MONTH( 日 ) 、 HOUR_OF_DAY( 時 ) 、 MINU

TE 、 SECOND 、 DAY_OF_WEEK(週 ) 等 , 這些都是在 Calendar 中所定義的靜態具名常數。

▪ Calendar 的 set() 也可直接指定年月日等資料 , 包括 set(年 ,月 , 日 ) 、 set(年 ,月 , 日 ,小時 (24), 分 ) 、及 set(年 ,月 , 日 , 時 , 分 ,秒 ), 其中的參數均為 int 。

▪ 代表月份的數值是由 0 開始 , 所以一月是 0, 二月是 1... ;而代表星期的數值 , 則星期日為 1, 星期一為 2..., 以此類推。

Page 90: SCJP ch17

90

Date 與 Calendar 類別的應用

請注意 , 由於 Calendar 為抽象類別 , 所以在建立 Calendar 時不可直接用 new 來建構 , 而必須呼叫其靜態方法 Calendar.getInstance(), 來動態建立並傳回一個 Calendar 的子物件。

其原因主要是因為不同語系在處理日期時間時可能會有一些差異 , 因此 Java 會針對這些差異來建立不同的 Calendar 子類別。有關語系的部份我們稍後會介紹。

Page 91: SCJP ch17

91

Date 與 Calendar 類別的應用

另外 , 月曆的 add() 和 roll() 都可針對指定欄位 ( 例如月、日、或分 ) 來加減數值 , 而二者的差異是 roll() 不會進位 , 例如將月曆的日期加 12 個月後 ,

使用 add() 時年份會加 1, 而使用 roll() 則年份不變。

底下來看範例。

Page 92: SCJP ch17

92

Date 與 Calendar 類別的應用

Page 93: SCJP ch17

93

Date 與 Calendar 類別的應用

1.第 6 行在印出 d 時 , 由於需轉為字串 , 因此會自動呼叫其 toString() 方法。

Page 94: SCJP ch17

94

Date 與 Calendar 類別的應用

2. 第 11 、 13 行的 DAY_OF_WEEK 、 MONTH 都是 Calendar 的公開靜態常數 , 因此透過物件 (c) 或類別名稱 Calendar 來存取都可以。在讀取星期幾時 , 會傳回代表星期的數值 (星期日為 1, 星期一為 2...), 所以要減 1 才行。但如果是讀取月份 , 例如 c.get(c.MONTH), 則要加 1 (因為一月是 0) 。

3. 第 14 行 getTime() 會傳回 Date 物件 , 並自動呼叫其 toString() 方法將內容轉為字串。

Page 95: SCJP ch17

95

Date 的另一種用法

Date 物件中其實是儲存著一個 long 的變數 , 代表距 1970/1/1 凌晨以後多少毫秒 (千分之一秒 ) 的日期 / 時間。因此我們也可以使用以下方法來操作:

▪ 這些方法雖然很少用到 , 但偶而會出現在 SCJP 考題中 , 所以還是稍微了解一下比較好。

Page 96: SCJP ch17

96

17-4-2 國際化的 Locale 類別

java.util.Locale 類別可用來建立代表特定國別語系的物件 , 以便搭配稍後會介紹的 java.text.DateFormat 、java.text.NumberFormat 等格式化的類別 , 來輸出 /

輸入特定語系的日期、數值、貨幣等資料。 以下是 Locale 的建構方法:

Page 97: SCJP ch17

97

國際化的 Locale 類別

其中的參數 language 為『 ISO 語言碼』 , 例如中文為 "zh" ;而 country 則為『 ISO 國家碼』 , 例如台灣為 "TW" 。

另外 , Locale 中也定義了一組代表國家、語系的靜態常數 , 例如 Locale.TRADITIONAL_CHINESE 代表繁體中文語系 , 而 Locale.TAIWAN 則代表台灣。

若要查詢 Locale 物件所代表的語系或國家 , 則可使用 getDisplayLanguage() 或 getDisplayCountry()

方法。

Page 98: SCJP ch17

98

國際化的 Locale 類別

這二個方法也可在參數中指定要使用哪種語言來輸出查詢結果 , 底下是範例:

Page 99: SCJP ch17

99

國際化的 Locale 類別

Page 100: SCJP ch17

100

17-4-3 格式化日期的 DateFormat 類別

當我們要輸出 ( 入 ) 特定樣式或語系的日期字串時 ,

就可使用 java.text.DateFormat 類別。 DateFormat 也是一個抽象類別 , 同樣要使用靜態方法來建立其子物件:

Page 101: SCJP ch17

101

格式化日期的 DateFormat 類別

其中第 2 、 3 個方法的參數也可以省略 , 但須由最後的參數開始往前省略。省略的參數即使用預設值 (SHORT 樣式及系統語系 ) 。

常用的樣式有 SHORT(短 ) 、 MEDIUM( 中 ) 、 LON

G(長 ) 、 FULL(完整 ) 等。 要將日期格式化為字串時 , 可使用 format() 方法;若要解析特定格式的日期字串 , 則可使用 parse(St r

ing s ) 方法 , 但如果格式不對 , 則會丟出 ParseEx

ception 的例外 , 此例外要在程式中捕捉 (catch) 或宣告 (throws) 。

Page 102: SCJP ch17

102

格式化日期的 DateFormat 類別

底下來看範例:

Page 103: SCJP ch17

103

格式化日期的 DateFormat 類別

Page 104: SCJP ch17

104

格式化日期的 DateFormat 類別

請注意 , 我們在第 3 行靜態匯入了 DateFormat

的所有靜態成員 , 因此可在程式中直接使用其靜態的方法及變數 , 而不用加上類別名稱 ( 例如第 8 、 1

1 行 ) 。

Page 105: SCJP ch17

105

17-4- 4 格式化數值與貨幣的 NumberFormat 類別 相對於前面介紹的 java.text.DateFormat 類別 , java.

text.NumberFormat 類別則是專門用來輸出 ( 入 )

特定格式的數值與貨幣。 同樣的 , NumberFormat 也是一個抽象類別 , 要使用靜態方法來建立其子物件:

Page 106: SCJP ch17

106

格式化數值與貨幣的 NumberFormat 類別

此類別除了提供前面已介紹過的 format() 及 parse

() 方法外 , 常用的還有:讀取、設定最大小數位數的 getMaximumFractionDigits( ) 、 setMaximumFractio

nDigits(int i), 最少小數位數的 getMinimumFraction

Digits() 、 setMinimumFractionDigits(int i), 以及設定只解析整數部份的 setParseIntegerOnly(boolean b)

等方法。 底下是範例。

Page 107: SCJP ch17

107

格式化數值與貨幣的 NumberFormat 類別

Page 108: SCJP ch17

108

格式化數值與貨幣的 NumberFormat 類別

Page 109: SCJP ch17

109

格式化數值與貨幣的 NumberFormat 類別

Page 110: SCJP ch17

110

格式化數值與貨幣的 NumberFormat 類別

1. 在第 3 、 4 行靜態匯入了 Locale 及 NumberFo

rmat 的所有靜態成員 , 因此可在程式中直接使用其靜態的方法或變數 ( 例如第 8 、 12 行 ) 。

2. 第 23 行設定 nf 物件只解析整數部份 , 然後在第 25 行解析一個數值字串。不過請注意 , 在執行 pa

rse() 時要處理 ParseException 例外 , 否則會編譯錯誤。

Page 111: SCJP ch17

111

17-5 使用 Regex 來搜尋與分解字串

在第 10 章已介紹過規則表示法 (Regular Expressi

on, 簡稱 regex), 並可用在 String 的幾個方法上:

Page 112: SCJP ch17

112

使用 Regex 來搜尋與分解字串

以上這些還只是較陽春的功能 , 為了讓我們更方便、更有效率地搜尋或分解文字 , Java 另外提供了 3 個實用的類別:

Page 113: SCJP ch17

113

17-5-1 搜尋字串的 Pattern 與 Matcher 類別 如果想用迴圈來一一找出字串中符合 regex 的部份 ,

那麼使用 java.util.regex.Pattern 及 java.util.rege

x.Matcher 來搜尋是最方便而有效率的了。底下就來看範例:

Page 114: SCJP ch17

114

搜尋字串的 Pattern 與 Matcher 類別

Page 115: SCJP ch17

115

搜尋字串的 Pattern 與 Matcher 類別

1.第 5 行用靜態方法 Pattern.compile() 來編譯 reg

ex ( 第一個命令列參數 ) 並傳回 Patern 物件 , 在第 7 行則用此物件的 matcher() 方法 , 來傳回可搜尋第二個命令列參數的 Matcher 物件。

2.第 9 行呼叫 Matcher 物件的 find() 方法以尋找下一個符合 regex 的子字串 , 該方法會傳回是否找到的布林值。第 10 行的 start() 會傳回找到的位置 (由 0 算起 ), end() 傳回找到字串之後的下一個位置 , 而 group() 則傳回找到的字串內容。

Page 116: SCJP ch17

116

搜尋字串的 Pattern 與 Matcher 類別

3. 本例是尋找第一字為數字 (\d), 且第二字為英數字或底線 (\w) 的字串。有一點要注意 , 就是找過的字元就不會再找了 , 例如第二次找到 12 之後 , 接著會由 3 開始找起 ,

而不是由 2 開始找起。

Page 117: SCJP ch17

117

regex 中使用量詞的注意事項 在 regex 中若使用 ? 、 * 、 + 等限制次數的量詞 , 預設會找出最長的符合字串 , 例如用前面的程式來搜尋以 b 結尾的任意字串:

程式會找出最長符合的字串 , 而不會找出較短的 "aab" 或 "b" 。如果希望由字串開頭 (由左往右 ) 找出較短字串 , 則可在量詞後面多加一個 ? (即 ?? 、*? 、 +?), 例如:

Page 118: SCJP ch17

118

regex 中使用量詞的注意事項

另外 , 在使用 ? 或 * 時 , 0 長度的字串也會被搜尋出來 , 例如:

Page 119: SCJP ch17

119

17-5-2 分解字串的類別 Scanner

String 的 split() 只能將字串一次全部分解為陣列 ,

而 java.util.Scanner 類別則提供了更豪華的功能:1. 可用迴圈的方式來逐一分解字串 , 以便做進一步的處

理 , 或隨時中止迴圈。

2. 可由字串中解析指定型別的資料 , 例如 nextInt() 可由字串中取出一個整數資料。

3. 可由檔案、鍵盤、字串等串流來建構 Scanner 物件 ,

並做為解析的來源資料。

Page 120: SCJP ch17

120

分解字串的類別 Scanner

Scanner 預設的分隔符號為連續空白 , 但我們也可用 useDelimeter(String pattern) 來指定一個 regex

樣式做為分隔。 每次要讀取下一個片斷 (Token) 時 , 則可使用 nex

t() 方法傳回片斷字串 , 或使用 nextXxx() 方法 (Xx

x 表 Char 以外的基本型別 ) 讀取片斷並轉為指定的型別。

而 hasNext() 及 hasNextXxx() 則可用來判斷是否還有下一個字串 , 或還有可轉為 Xxx 型別的資料片斷。

Page 121: SCJP ch17

121

分解字串的類別 Scanner

底下範例以預設的連續空白為分隔 , 分別用解析字串與解析資料型別的方式 , 來解析命令列傳入的參數:

Page 122: SCJP ch17

122

分解字串的類別 Scanner

Page 123: SCJP ch17

123

分解字串的類別 Scanner

Page 124: SCJP ch17

124

17-A 求任意次方根

Page 125: SCJP ch17

125

1. Given:

What is the result?

A. short, Long B. Short, Long C. Short, ShortD. Compilation fails. E. An exception is thrown at runtime..

Page 126: SCJP ch17

126

Page 127: SCJP ch17

127

2. What is the result of following program?

A. int B. short C. Short D. Compilation fails. E. An exception is thrown at runtime.

Page 128: SCJP ch17

128

3. Please place the correct Answers to the Output empty boxes.

Page 129: SCJP ch17

129

4. What 's the result of following Code?

A. 3B. 3.141593C. %dD. Compilation fails.E. An Exception is thrown at runtime.

Page 130: SCJP ch17

130

5. What will be the result if current day is 2009/10/31?

A. 31-Dec-2009 B. Dec 31, 2009 C. 31/12/09D. Compile fails at line 8. E. Compile fails at line 6 and 8.F. An exception is thrown at runtime.

Page 131: SCJP ch17

131

6. What is the result? (Choose two.)

A. s1 = 3 B. s1 = 3.142 C. s1 = 3.141593

D. s2 = 5 E. s2 = 5.0 F. s2 = 5.00

Page 132: SCJP ch17

132

7. What is the result of following code?

A. 3 B. 8 C. 0

D. Compilation fails. E. An exception is thrown at runtime.

Page 133: SCJP ch17

133

7. Given:

Which codes, insert at line 7, will get the default country name and current date?

Page 134: SCJP ch17

134

A. A .Locale loc = Locale.getDefault();String s = loc.getDisplayCountry() + f.setFormat(d);

B. B. Locale loc = Locale.getDefault();String s = loc.getDisplayCountry() + f.format(d);

C. C. Locale loc = Locale.getLocale();String s = loc.getDisplayCountry() + f.setFormat(d);

D. D. Locale loc = Locale.getLocale();String s = loc.getDisplayCountry() + f.format(d);