谜题61:日期游戏
下面的程序演練了Date和Calendar類的某些基本特性,它會(huì)打印出什么呢?
import java.util.*;public class DatingGame {public static void main(String[ ] args) { Calendar cal = Calendar.getInstance(); cal.set(1999, 12, 31); // Year, Month, Day System.out.print(cal.get(Calendar.YEAR) + " "); Date d = cal.getTime(); System.out.println(d.getDay()); } }該程序創(chuàng)建了一個(gè)Calendar實(shí)例,它應(yīng)該表示的是1999年的除夕夜,然后該程序打印年份和日。看起來該程序應(yīng)該打印1999 31,但是它沒有;它打印的是2000 1。難道這是致命的Y2K(千年蟲)問題嗎?
不,事情比我們想象的要糟糕得多:這是致命的Date/Calendar問題。在Java平臺(tái)首次發(fā)布時(shí),它唯一支持日歷計(jì)算類的就是Date類。這個(gè)類在能力方面是受限的,特別是當(dāng)需要支持國際化時(shí),它就暴露出了一個(gè)基本的設(shè)計(jì)缺陷:Date實(shí)例是易變的。在1.1版中,Calendar類被添加到了Java平臺(tái)中,以矯正Date的缺點(diǎn),由此大部分的Date方法就都被棄用了。遺憾的是,這么做只能使情況更糟。我們的程序說明Date和Calendar API有許多問題。
該程序的第一個(gè)bug就位于方法調(diào)用cal.set(1999,12,31)中。當(dāng)月份以數(shù)字來表示時(shí),習(xí)慣上我們將第一個(gè)月被賦值為1。遺憾的是,Date將一月表示為0,而Calendar延續(xù)了這個(gè)錯(cuò)誤。因此,這個(gè)方法調(diào)用將日歷設(shè)置到了1999年第13個(gè)月的第31天。但是標(biāo)準(zhǔn)的(西歷)日歷只有12個(gè)月,該方法調(diào)用肯定應(yīng)該拋出一個(gè)IllegalArgumentException異常,對嗎?它是應(yīng)該這么做,但是它并沒有這么做。Calendar類直接將其替換為下一年,在本例中即2000年的第一個(gè)月。這也就解釋了我們的程序?yàn)槭裁创蛴〕龅牡谝粋€(gè)數(shù)字是2000。
有兩種方法可以訂正這個(gè)問題。你可以將cal.set調(diào)用的第二個(gè)參數(shù)由12改為11,但是這么做容易引起混淆,因?yàn)閿?shù)字11會(huì)讓讀者誤以為是11月。更好的方式是使用Calendar專為此目的而定義的常量,即Calendar.DECEMBER。
該程序打印出的第二個(gè)數(shù)字又是怎么回事呢?cal.set調(diào)用很明顯是要把日歷設(shè)置到這個(gè)月的第31天,Date實(shí)例d表示的是與Calendar相同的時(shí)間點(diǎn),因此它的getDay方法應(yīng)該返回31,但是程序打印的卻是1,這是怎么搞得呢?
為了找出原因,你必須先閱讀一下文檔,它敘述道Date.getDay返回的是Date實(shí)例所表示的星期日期,而不是月份日期。這個(gè)返回值是基于0的,從星期天開始計(jì)算。因此程序所打印的1表示2000年1月31日是星期一。請注意,相應(yīng)的Calendar方法get(Calendar.DAY_OF_WEEK) 不知為什么返回的是基于1的星期日期值,而不是像Date的對應(yīng)方法那樣返回基于0的星期日期值。
有兩種方法可以訂正這個(gè)問題。你可以調(diào)用Date.date這一名字極易讓人混淆的方法,它返回的是月份日期。然而,與大多數(shù)Date方法一樣,它已經(jīng)被棄用了,因此你最好是將Date徹底拋棄,直接調(diào)用Calendar的get(Calendar.DAY_OF_MONTH)方法。用這兩種方法,該程序都可以打印出我們想要的1999 31:
public class DatingGame {public static void main(String[] args) { Calendar cal = Calendar.getInstance(); cal.set(1999, Calendar.DECEMBER, 31); System.out.print(cal.get(Calendar.YEAR) + " "); System.out.println(cal.get(Calendar.DAY_OF_MONTH)); } }本謎題只是掀開了Calendar和Date缺陷的冰山一角。這些API簡直就是雷區(qū)。Calendar其他的嚴(yán)重問題包括弱類型(幾乎每樣事物都是一個(gè)int)、過于復(fù)雜的狀態(tài)空間、拙劣的結(jié)構(gòu)、不一致的命名以及不一致的雨衣等。在使用Calendar和Date的時(shí)候一定要當(dāng)心,千萬要記著查閱API文檔。
對API設(shè)計(jì)者來說,其教訓(xùn)是:如果你不能在第一次設(shè)計(jì)時(shí)就使它正確,那么至少應(yīng)該在第二次設(shè)計(jì)時(shí)應(yīng)該使它正確,絕對不能留到第三次設(shè)計(jì)時(shí)去處理。如果你對某個(gè)API的首次嘗試出現(xiàn)了嚴(yán)重問題,那么你的客戶可能會(huì)原諒你,并且會(huì)再給你一次機(jī)會(huì)。如果你第二次嘗試又有問題,你可能會(huì)永遠(yuǎn)堅(jiān)持這些錯(cuò)誤了。
轉(zhuǎn)載于:https://www.cnblogs.com/yuyu666/p/9840996.html
總結(jié)
- 上一篇: qq邮箱电脑登录入口(qq邮箱网上登录入
- 下一篇: 电脑硬盘扇区是什么(磁盘分区的扇区是什么