2013年9月3日 星期二

Math NumberFormat Date DateFormat

數字與日期的運算及格式化
作者: 許裕永

學習Java的重點,是學會如何應用類別。在前面的章節,我們學會了兩種類別應用的方式:
1、建構某一類別的物件,用物件執行實體方法成員。
2、用類別名稱呼叫類別方法成員。
本章將繼續以這兩種應用方式,使用Java提供的類別,來做數字與日期的運算及格式化。
 
1. Math
java‧lang‧Math類別中,宣告了相當多的類別方法成員,來協助設計師執行數學運算。
1-1 物件建構
在JDK說明文件中,Math類別並沒有提供建構方法,這表示Math類別不接受用new的方式來建構物件。
而且類別中宣告的方法,全部都是類別方法(static),所以也沒有必要建構物件。
 
1-2 重要方法
方法一:static 資料型別 abs(參數)
運算結果:參數的絕對值,運算結果的資料型別就是參數的型別。
 
方法二:static double ceil(double a)
運算結果:參數小數點第一位無條件進位後之值。
 
例一:
System.out.println(Math.ceil(8.4));
System.out.println(Math.ceil(-8.4));
列印結果:9‧0 -8‧0。兩點注意:1、運算結果的資料型別是double。2、-8‧4進位後為-8‧0不是-9‧0。
 
方法三:static double floor(double a) 
運算結果:參數小數點無條件捨去後之值。
 
方法四:資料型別 max(參數,參數)
運算結果:兩個參數的較大值,運算結果的資料型別就是參數的型別。
 
方法五:資料型別 min(參數,參數)
運算結果:兩個參數的較小值,運算結果的資料型別就是參數的型別。
 
方法六:double pow(double a, double b)
運算結果:參數a的參數b次方值。
 
例一:
System.out.println(Math.pow(2,3));
列印結果:8。
 
方法七:double random()
運算結果:大於等於0‧0而且小於1‧0的亂數。請注意,沒有等於1。
 
例一:
System.out.println(Math.random());
System.out.println((int)(Math.random()*10));
System.out.println((int)(Math.random()*10)+1);
System.out.println((int)(Math.random()*12345)%41+1);
第一行敍述句:列印一個有小數點的亂數。
第二行敍述句:列印0~9之間的整數亂數。
第三行敍述句:列印1~10之間的整數亂數。
第四行敍述句:列印1~42之間的整數亂數。
 
方法八:資料型別 round(參數) 
運算結果:參數四捨五入的運算。若參數型別為double則運算結果的資料型別為long;
若參數型別為float則運算結果的資料型別為int。
請注意若參數值為負值時,其進位方式為-0‧1~-0‧5進位;-0‧6~-0‧9捨去。
 
例一:
System.out.println(Math.round(3.5));
System.out.println(Math.round(-3.5));
System.out.println(Math.round(-3.6));
列印結果:4 -3 -4。
第二行敍述句中的參數-3‧5,其-0‧5需進位,但因為是負值,所以進位方式是取消小數點後的值(-3>-3‧5)。
第三行敍述句中的參數-3‧6,其-0‧6需捨去,但因為是負值,所以捨去方式是取消小數點後的值再減1(-4<-3‧6)。
總而言之,無論正負值,其小數點後第一個位數的值,接近1的5個值執行整數值加1
(正值的0‧5~0‧9,負值的-0‧1~-0‧5);
剩下的4個值執行整數值減1。
 
例二:
int a=Math.round(3.5);
本敍述句會造成編譯錯誤,因為參數3‧5是double的型別,所以Math‧round(3‧5)運算結果的型別為long,
而變數a的資料型別是int。
 
方法九:double sqrt(double a)
運算結果:參數開根號之值。
 
Math中還有一些比較特殊的方法,如指數與對數或三角函數的運算,請有用到的讀者自行練習。
 
2. NumberFormat
Math類別只提供數字運算的方法,而運算後的值若要以特定的格式輸出,
就要使用package java‧text中的NumberFormat類別。
 
2-1 物件建構
NumberFormat類別是一個抽象類別(abstract),抽象類別不可以直接建構成物件(後續章節介紹),
雖然JDK文件中有宣告一個建構方法,還是不能用new來建構物件。
但是用來格式化數值的方法:format(參數)。是一個實體方法成員,也就是必須用物件才能呼叫的方法。
所以如何建構抽象類別的物件,再用該物件來呼叫實體方法成員,就是本節的重點了。
 
2-2 重要方法
方法一:static NumberFormat getInstance()
運算結果:建構一個預設格式的NumberFormat類別的物件(取小數點後三位數)。
 
方法二:String format(參數)
運算結果:將參數依照執行本方法的NumberFormat物件中的格式設定值,來建構String物件。
 
例一:
NumberFormat nf=NumberFormat.getInstance();
System.out.println(nf.format(1.23456789));
System.out.println(NumberFormat.getInstance().format(1.23456789));
列印結果:1‧235 1‧235。
本例主要是介紹NumberForamt物件的取得:敍述句NumberFormat‧getInstance(),
便會建構一個NumberFormat物件,至於要不要把這個物件的物件代號指派給參數,則由設計師自行決定。
像第三行敍述句中,NumberFormat物件建構後便可以直接呼叫實體方法成員。
只不過若該物件要重複使用,當然是指派給參考變數會比較方便。
特別注意:程式碼最上面請引入所使用類別的package。
import java‧text‧*;
 
方法三:setMaximumFractionDigits(int newValue)
運算結果:設定本物件格式化數字時的最大小數點位數值(預設值為小數點後3位),大於此位數之數字以四捨五入方式進位。
 
方法四:setMinimumFractionDigits(int newValue)
運算結果:設定本物件格式化數字時的最小小數點位數值,(預設值為小數點後0位),不足此位數時補0。
 
例一:
NumberFormat nf=NumberFormat.getIntegerInstance();
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
System.out.println(nf.format(1.234));
System.out.println(nf.format(1.2));
列印結果:1‧23 1‧20。
 
方法五:NumberFormat getCurrencyInstance() 
運算結果:建構一個可以將數值格式化為貨幣樣式的NumberFormat物件。
 
方法六:NumberFormat getIntegerInstance()
運算結果:建構一個可以將數值格式化為整數的NumberFormat物件。
 
了解Wrapper Classes的重要性,如果不夠熟練,就會連不是很複雜的範例,都會寫的很複雜,甚至寫不出來!
 
3. Date
Java提供了一個可建構記錄日期及時間物件的類別。類別名稱:java‧util‧Date。
 
3-1物件建構
JDK文件中,Date的建構方法共有六個。沒有參數的建構方法建構的是:「以程式執行時的日期及時間為值的物件」。
有參數的建構則是以參數值來建構物件。比較特殊的是以long型別的值為參數的建構方法,
其值是以千分之一秒為單位,以1970年1月1日8點0分0秒為基準。
 
3-2 重要方法
方法一:int getXxx()
運算結果:取得Date物件中的指定值。Xxx指的是:
Year、Month、Date、Day、Hours、Minutes、Seconds。
Year:以1900年為起始年。
Month:以0為起始月。
Date:取得以月為單位的日。
Day:取得以星期為單位的日(例:星期一)。
 
方法二:void setXxx(參數)
運算結果:設定Date物件中的指定值。
 
4. DateFormat
 
4-1 物件建構
 
DateFormat類別和NumberFormat類別一樣,是抽象類別,不能直接建構成物件,而必須呼叫類別方法成員。
 
4-2 重要方法
 
方法一:DateFormat getXxxInstance()
運算結果:建構DateFormat類別物件。
 
Xxx指的是:Date、Time、DateTime。
Date:只格式化日期。
Time:只格式化時間。
DateTime:格式化日期及時間。
 
方法二:String format(Date d)
運算結果:以DateFormat物件的設定值,格式化Date型別的參數物件d為String物件。
 
例一:
Date d=new Date();
System.out.println(DateFormat.getDateInstance().format(d));
System.out.println(DateFormat.getTimeInstance().format(d));
System.out.println(DateFormat.getDateTimeInstance().format(d));
三個println中,分別建構了不同樣式的DateFormat物件,來顯示同一個Date物件。
 
5. Calendar
Date類別物件協助設計師記錄日期及時間,但它並不提供運算。
如果要運算今天的100天後是幾月幾日,Java有提供另一個類別:java‧util‧Calendar來協助運算。
 
5-1 物件建構
 
Calendar和NumberFormat及DateFormat一樣也是抽象類別。
也一樣必須呼叫類別方法getInstance()才能建構物件。
 
5-2 重要方法及類別常數成員
 
方法一:static Calendar getInstance()
運算結果:建構Calender物件。此物件中記錄著執行此程式的作業系統中所有與日期及時間相關的訊息。
預設的日期及時間為執行本程式當時的日期及時間。
 
例一:
System.out.println(Calendar.getInstance());
列印結果:java.util.GregorianCalendar[time=1165992005734,areFieldsSet=true,areAllFieldsSet=true,lenient=true,
zone=sun.util.calendar.ZoneInfo[id="Asia/Taipei",offset=28800000,dstSavings=0,useDaylight=false,transitions=42,
lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2006,MONTH=11,WEEK_OF_YEAR=50,
WEEK_OF_MONTH=3,DAY_OF_MONTH=13,DAY_OF_YEAR=347,DAY_OF_WEEK=4,
DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=40,SECOND=5,
MILLISECOND=734,ZONE_OFFSET=28800000,DST_OFFSET=0]
從以上的列印的結果可以知道它包含了所有日期與時間相關的資訊,但是如何取得適當的資料來運算,就必須熟練其他的方法。
 
方法二:int get(int field)
取得指定欄位的資料。
 
例一:
Calendar c=Calendar.getInstance();
System.out.println(":" + c.get(1));
System.out.println(":" + c.get(2)+1);
System.out.println(":" + c.get(5));
列印結果:執行時的年、月、日。但月數的值是以0為起點,所以必須加1。
 
方法三:Date getTime()
運算結果:以Calendar物件中的年、月、日、時、分、秒的值建構一個Date類別的物件。
 
例一:
Calendar c=Calendar.getInstance();
Date d=c.getTime();
System.out.println(DateFormat.getDateTimeInstance().format(d));
列印結果:目前的日期及時間格式化後的值。
 
方法四:void set(參數)
運算結果:設定Calendar物件中指定的值。參數可以指定某一個或一個以上欄位的值(請參閱JDK文件)。
 
方法五:void setTime(Date d)
運算結果:將Date類別的參數物件d所包含的日期及時間值,設定成為Calendar物件中的日期及時間值。
 
方法六:void add(int field, int amount) 
運算結果:把指定的欄位(field),新增指定的數量(amount)。
 
例一:
Calendar c=Calendar.getInstance();
Date d=new Date(107,0,1);
c.setTime(d);
c.add(5,100);
System.out.println(DateFormat.getDateInstance().format(c.getTime()));
列印結果:2007/4/11。
Date物件中包含的日期值為2007/1/1,把它設定成Calendar物件中的日期。
再用呼叫add(5,100)來指定新增5(日)這個欄位的值,新增的量為100,表示運算Calendar物件100天後的日期。
最後再呼叫Calendar物件的getTime()來取得Date物件並置於DateFormat物件的format()中當參數來列印。
 
方法七:void roll(int field, int amount) 
運算結果:以不進位的方式把指定欄位(field),新增指定數量(amount)。
 
例一:
Calendar c=Calendar.getInstance();
Date d=new Date(107,0,1);
c.setTime(d);
c.roll (5,100);
System.out.println(DateFormat.getDateInstance().format(c.getTime()));
列印結果:2007/1/8。
因為是以不進位方式運算,所以滿31天時,月份的值並不會進1。
 
5-3 類別常數成員
 
在剛才方法的範例中,相信大部份的讀者都有一個很大的疑問:
當呼叫get或set的方法時,欄位的代表值是怎麼得到的?要怎樣才知道1代表年,2代表月,5代表日呢?
那其他的欄位呢?是不是要背起來呢?
 
Java在大部份的類別中,都會針對一些常用的而且跟物件內容沒有直接關係的值,預存為類別常數成員,
來方便設計師使用。這些值因為和物件內容沒有直接關係,所以宣告static,可以讓設計師用類別名稱呼叫。
這些值不接受使用者變更,所以宣告為final。為了方便辯識,這些常數的名稱,大部份是用大寫字母來命名。
這些值的明細可以在JDK文件中,每個類別的Field Summary中查閱。
 
例一:
Calendar c=Calendar.getInstance();
System.out.println(":" + c.get(Calendar.YEAR));
System.out.println(":" + c.get(Calendar.MONTH)+1);
System.out.println(":" + c.get(Calendar.DATE));
用類別名稱可以取得這些常數的值,上述的常數均代表一個int型別的值(用物件名稱也可以取得,和類別方法成員的使用方式是一樣的)。
 
6. Locale
無論是NumberFormat或DateFormat或Calendar的物件,其預設的格式均為通用格式,
若希望設定為特定區域的格式,就必須在getInstance()時,指定區域物件。
Java中提供了一個java‧util‧Locale類別,來建構區域物件。
 
6-1 類別常數成員
 
雖然Locale類別有提供建構方法,可以讓設計師依照語言,城市等參數來建構物件。
但要了解每個區域或城市或國家的語言也是一件頭痛的事。所以Java在Locale類別,
已經在Filed Summary中預設了許多的Locale物件,方便設計師使用。
 
例一:
NumberFormat nf=NumberFormat.getInstance(Locale.TAIWAN);
System.out.println(nf.format(1234.5678));
NumberFormat nf2=NumberFormat.getInstance(Locale.GERMAN);
System.out.println(nf2.format(1234.5678));
列印結果:1,234.568 1.234,568。
第二個為德國的數字格式。
 
例二:
DateFormat df=DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.MEDIUM,Locale.TAIWAN);
System.out.println(df.format(new Date()));
列印結果:2006年12月13日 星期三 下午 04:57:32。
此例中DateFormat呼叫的getDateTimeInstance()中,
有三個參數。第一個是指定日期樣式,第二個是指定時間樣式,第三個是指定區域。
其中的第一個及第二個使用的是Date類別中宣告的類別常數成員。總共有四個:
FULL,LONG,MEDIUM,DEFAULT。分別代表完整的、長的、短的及預設的,讀者可自行測試。
 
7. 認證重點
7-1 Math
  • Math類別並沒有提供建構方法,而且類別中宣告的方法,全部都是類別方法成員(static)。
  • Math‧round(參數)的運算結果:參數四捨五入的運算。
  • 若參數型別為double則運算結果的資料型別為long;
  • 若參數型別為float則運算結果的資料型別為int。
  • 請注意若參數值為負值時,其進位方式為-0‧1~-0‧5進位;-0‧6~-0‧9捨去。
  • Math‧random()運算結果:大於等於0‧0而且小於1‧0的亂數。請注意,沒有等於1。
  • 7-2 NumberFormat
    • NumberFormat類別是一個抽象類別(abstract),不可以直接建構成物件。
    7-3 Date
  • 以long型別的值為參數的建構方法,其值是以千分之一秒為單位,以1970年1月1日8點0分0秒為基準。
  •  指派Date物件的日期時,年是以1900年為起點,月是以0為起點。
  • 7-4 DateFormat
  • DateFormat類別和NumberFormat類別一樣,是抽象類別,不能直接建構成物件,而必須呼叫類別方法成員。
  • 7-5 Calender
  •  Calendar和NumberFormat及DateFormat一樣也是抽象類別。也一樣必須呼叫類別方法getInstance()才能建構物件。
  • add及roll的差異性。
  •  取得及設定Date物件的應用。
  • 類別常數成員的使用。
  • 7-6 Locale
    • 無論是NumberFormat或DateFormat或Calendar的物件,其預設的格式均為通用格式,若希望設定為特定區域的格式,就必須在getInstance()時,指定區域物件。

    沒有留言:

    張貼留言

    注意:只有此網誌的成員可以留言。