摘要
作為企業(yè)Java開發(fā)人員,我們總是需要實(shí)現(xiàn)各種功能,如解析XML、使用HTTP、驗(yàn)證輸入以及處理日期等。使用Jakarta Commons項(xiàng)目的目的在于創(chuàng)建負(fù)責(zé)處理所有此類常用任務(wù)的組件,從而節(jié)約時(shí)間,讓您集中精力處理核心業(yè)務(wù)解決方案。在本文中,我們將對(duì)Jakarta Commons 項(xiàng)目作簡(jiǎn)單介紹,然后演示如何使用Jakarta Commons內(nèi)的Lang組件來處理和簡(jiǎn)化日常Java任務(wù),比如字符串操作、使用日期和日歷、比較數(shù)據(jù)對(duì)象以及對(duì)象排序等。對(duì)于本文中的所有例子,我們都將使用最新的Lang版本(即2.1版本)。
編者按:本文中的代碼是根據(jù)Commons Lang的 RC1版本 編寫的。其最終版不久將發(fā)行。
Commons和Lang組件簡(jiǎn)介
Jakarta Commons 項(xiàng)目旨在實(shí)現(xiàn)可重用的 Java 組件。此項(xiàng)目包含數(shù)十個(gè)組件,用以簡(jiǎn)化 Java 的開發(fā),每個(gè)組件負(fù)責(zé)滿足一個(gè)特定需求。有大量的組件可用,且不僅限于在特定類型的Java應(yīng)用程序中使用。
項(xiàng)目分類在兩個(gè)部件中:
目前Commons Proper中有33個(gè)項(xiàng)目,Commons Sandbox中有22個(gè)項(xiàng)目,故而,任何一類Java項(xiàng)目都有其存在的意義。
Lang組件是Jakarta Commons中較為流行的組件之一。Lang是要呈現(xiàn)在J2SE本身中的一組類。
在本文中,我們將了解Lang最有用的一些功能。要注意的是,也可以只使用基本Java類來完成Lang的每個(gè)功能,但相對(duì)于自己學(xué)習(xí)、理解并編寫代碼而言,使用Lang要簡(jiǎn)單得多。即使您能夠?qū)懗鲎詈玫拇a,使用經(jīng)過實(shí)驗(yàn)和測(cè)試的Lang的功能會(huì)更快一些,能節(jié)省大量的檢查與測(cè)試時(shí)間。隨著Lang一起提供了特有的JUnit測(cè)試用例,Lang的使用極其廣泛,已經(jīng)歷了其創(chuàng)建者和現(xiàn)實(shí)世界的種種考驗(yàn)。
Lang的一個(gè)重要特征是其簡(jiǎn)單性。通常來說,新的Java組件十分復(fù)雜,要了解若干種技術(shù)才能使用這些組件。要理解組件的用途通常都很難,更別說實(shí)際使用該組件了。但對(duì)于大多數(shù)Commons組件而言,這就不是問題了。Lang一類組件使用方便,無論對(duì)Java初學(xué)者還是高級(jí)Java用戶都非常有用。
如果在采用技術(shù)前需要有十足的保證,則請(qǐng)?jiān)诒4婺腏ava軟件的目錄中搜索commons-lang*.jar。結(jié)果會(huì)讓您感到很意外。 Tomcat、Struts、Hibernate、Spring和WebWork 等常見Java項(xiàng)目都使用Lang。
首先讓我們看一看使用Lang進(jìn)行大多數(shù)開發(fā)人員幾乎每天必須進(jìn)行的操作——字符串操作。
處理字符串
無論應(yīng)用程序是基于Swing、J2EE或J2ME的,它都必須使用字符串。所以,盡管在Java中使用字符串相當(dāng)簡(jiǎn)單,但是如果希望按照一定的條件修改和處理字符串,事情就不那么簡(jiǎn)單了。您不得不在各種與字符串相關(guān)的類中尋找各種不常用的方法,然后想辦法使其協(xié)同工作,以獲得所需的結(jié)果。雖然有些Lang方法與J2SE中的某些方法重疊,但在大多數(shù)情況下,一個(gè)Lang方法就可提供各種類中的多個(gè)J2SE方法的功能,從而幫助您獲得所需的輸出。
Lang組件有許多專門用于字符串操作的類。現(xiàn)在我們將使用一個(gè)簡(jiǎn)單的Java應(yīng)用程序來演示一些較為有用的類和方法。
當(dāng)應(yīng)用程序接受用戶輸入時(shí),由于用戶可能會(huì)存在輸入錯(cuò)誤的情況,或用戶可能以各種格式輸入數(shù)據(jù),而您希望只采用一種格式進(jìn)行處理和存儲(chǔ),則通常會(huì)涉及到對(duì)字符串進(jìn)行操作。
例如,您有一個(gè)帶輸入框的窗體,用戶在此輸入框內(nèi)輸入許可證密鑰。您希望允許輸入1111-JAVA格式的密鑰。您必須進(jìn)行以下操作:
只有當(dāng)密鑰滿足所有這些條件時(shí),應(yīng)用程序才會(huì)查詢數(shù)據(jù)庫(kù),檢查該密鑰是否合法。
如果不花大量的時(shí)間瀏覽String、StringTokenizer和其他類的API文檔,您能完成以上的任務(wù)么?我不能,所以現(xiàn)在我將試著用Lang組件來管理驗(yàn)證。
清單1. checkLicenseKey()方法
/** * Check if the key is valid * @param key license key value * @return true if key is valid, false otherwise. */public static boolean checkLicenseKey(String key){ //checks if empty or null if(StringUtils.isBlank(key)){ return false; } //delete all white space key= StringUtils.deleteWhitespace(key); //Split String using the - separator String[] keySplit = StringUtils.split(key, "-"); //check lengths of whole and parts if(keySplit.length != 2 || keySplit[0].length() != 4 || keySplit[1].length() != 4) { return false; } //Check if first part is numeric if(!StringUtils.isNumeric(keySplit[0])){ return false; } //Check if second part contains only //the four characters ‘J‘, ‘A‘, ‘V‘ and ‘A‘ if(! StringUtils.containsOnly(keySplit[1] ,new char[]{‘J‘, ‘A‘, ‘V‘, ‘A‘})){ return false; } //Check if the fourth character //in the first part is a ‘0‘ if(StringUtils.indexOf(keySplit[0], ‘0‘) != 3){ return false; } //If all conditions are fulfilled, key is valid. return true;}在清單1中,我們使用了org.apache.commons.lang.StringUtils類中提供的各種方法,根據(jù)我們先前定義的所有規(guī)則對(duì)字符串進(jìn)行驗(yàn)證。isBlank()方法檢查字符串是否為空。deleteWhitespace()方法確保字符串不包含空格。然后我們使用split()方法對(duì)字符串進(jìn)行分隔,并使用isNumeric()、containsOnly()和indexOf()方法對(duì)密鑰的兩部分進(jìn)行驗(yàn)證。
public static void main(String[] args) { String []key= {"1210-JVAJ","1211-JVAJ", "210-JVAJ", "1210-ZVAJ"}; for (int i=0; i < key.length; i++){ if(checkLicenseKey(key[i])){ System.out.println(key[i]+ " >> Is Valid"); } else{ System.out.println(key[i]+ " >> Is InValid"); } }}清單3. 輸出
1210-JVAJ >> Is Valid1211-JVAJ >> Is InValid210-JVAJ >> Is InValid1210-ZVAJ >> Is InValid大部分用于進(jìn)行字符串操作的方法都隸屬于org.apache.commons.lang.StringUtils,但也有其他的類可以使用。CharUtils和CharSetUtils分別提供使用字符和字符集的實(shí)用方法。WordUtils是在2.0版中首次出現(xiàn)的類,用于承載專門用于處理字的實(shí)用方法。不過,由于字符串和字的處理上有大量的重疊操作,使得此類似乎有點(diǎn)沒有存在的必要了。RandomStringUtils類可以根據(jù)各種規(guī)則生成隨機(jī)字符串。
public static void main(String[] args) throws InterruptedException, ParseException { //date1 created Date date1= new Date(); //Print the date and time at this instant System.out.println("The time right now is >>"+date1); //Thread sleep for 1000 ms Thread.currentThread().sleep(DateUtils.MILLIS_IN_SECOND); //date2 created. Date date2= new Date(); //Check if date1 and date2 have the same day System.out.println("Is Same Day >> " + DateUtils.isSameDay(date1, date2)); //Check if date1 and date2 have the same instance System.out.println("Is Same Instant >> " +DateUtils.isSameInstant(date1, date2)); //Round the hour System.out.println("Date after rounding >>" +DateUtils.round(date1, Calendar.HOUR)); //Truncate the hour System.out.println("Date after truncation >>" +DateUtils.truncate(date1, Calendar.HOUR)); //Three dates in three different formats String [] dates={"2005.03.24 11:03:26", "2005-03-24 11:03", "2005/03/24"}; //Iterate over dates and parse strings to java.util.Date objects for(int i=0; i < dates.length; i++){ Date parsedDate= DateUtils.parseDate(dates[i], new String []{"yyyy/MM/dd", "yyyy.MM.dd HH:mm:ss", "yyyy-MM-dd HH:mm"}); System.out.println("Parsed Date is >>"+parsedDate); } //Display date in HH:mm:ss format System.out.println("Now >>" +DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(System.currentTimeMillis()));}清單4演示了org.apache.commons.lang.DateUtils和org.apache.commons.lang.DateFormatStringUtils類的部分功能。還有其他許多方法可以進(jìn)行同樣的操作,但輸入格式不同。故而,如果萬一您必須分析和格式化一個(gè)日期值,只需要借助提供的方法之一,利用一行代碼就可以實(shí)現(xiàn)了。
The time right now is >>Sat Apr 09 14:40:41 GMT+05:30 2005Is Same Day >> trueIs Same Instant >> falseDate after rounding >>Sat Apr 09 15:00:00 GMT+05:30 2005Date after truncation >>Sat Apr 09 14:00:00 GMT+05:30 2005Parsed Date is >>Thu Mar 24 11:03:26 GMT+05:30 2005Parsed Date is >>Thu Mar 24 11:03:00 GMT+05:30 2005Parsed Date is >>Thu Mar 24 00:00:00 GMT+05:30 2005Now >>14:40:43在清單4中,我們創(chuàng)建了兩個(gè)日期,這兩個(gè)日期僅有一秒的差別。然后使用isSameInstant()和isSameDay()方法檢查這兩個(gè)日期是否相同。接下來將日期進(jìn)行舍入和截?cái)?,然后使用在?shù)組中指定的各種格式對(duì)特殊日期用例進(jìn)行解析。
public class Computer { String processor; String color; int cost; /** Creates a new instance of Computer */ public Computer(String processor, String color, int cost) { this.processor=processor; this.color=color; this.cost=cost; } public static void main(String[] args) { Computer myComp=new Computer("Pentium","black",1000); System.out.println(myComp); } public String toString(){ return ToStringBuilder.reflectionToString(this); /* return ToStringBuilder.reflectionToString(this , ToStringStyle.SHORT_PREFIX_STYLE); return ToStringBuilder.reflectionToString(this , ToStringStyle.MULTI_LINE_STYLE); return new ToStringBuilder(this) .append("processor", processor).toString(); */ }}清單6演示了具有三個(gè)字段的Computer類。其中值得關(guān)注的是toString()方法。調(diào)用reflectionToString()方法可以判斷哪些是類中的字段,然后打印其名稱和值。main()方法中,我們只創(chuàng)建了該類的一個(gè)實(shí)例,然后將其打印出來。該類的輸出為dev2dev.Computer@f6a746[processor=Pentium,color=black,cost=1000]。
1) dev2dev.Computer@f6a746[processor=Pentium,color=black,cost=1000]2) Computer[processor=Pentium,color=black,cost=1000]3) dev2dev.Computer@f6a746[ processor=Pentium color=black cost=1000 ]4) dev2dev.Computer@192d342[processor=Pentium]對(duì)象比較與排序
public int compareTo(Object obj) { Computer anotherComputer = (Computer)obj; //return new CompareToBuilder().reflectionCompare(this, anotherComputer); return new CompareToBuilder(). append(this.cost, anotherComputer.cost).toComparison();}然后,為了實(shí)際進(jìn)行比較,我們編寫一個(gè)名為ComputerSor的簡(jiǎn)單類,如清單9中所示。我們只向ArrayList添加三個(gè)對(duì)象,然后進(jìn)行排序。
public class ComputerSort { public static void main(String[] args) { ArrayList computerList = new ArrayList(); computerList.add(new Computer("Pentium","black", 1000)); computerList.add(new Computer("Pentium","chocolate", 334)); computerList.add(new Computer("Pentium","darkgray", 2234)); Collections.sort(computerList); System.out.println(computerList); }}執(zhí)行ComputerSort時(shí),將看到對(duì)象根據(jù)cost字段的值進(jìn)行了排序。CompareToBuilder與ToStringBuilder類似,也有一個(gè)基于反射的用法選項(xiàng)。我們已對(duì)清單8中的compareTo()方法中的位元進(jìn)行了注釋,因?yàn)?,在此種情況下,反射選項(xiàng)將比較所有字段,最終獲得不正確的結(jié)果。如果既不希望比較當(dāng)前類中的字段,也不希望比較其超類中的字段,CompareToBuilder也提供了可以用于此用途的方法。執(zhí)行ComputerSort類的輸出如清單10中所示。
[dev2dev.Computer@cf2c80[processor=Pentium,color=chocolate,cost=334], dev2dev.Computer@12dacd1[processor=Pentium,color=black,cost=1000], dev2dev.Computer@1ad086a[processor=Pentium,color=darkgray,cost=2234]]
結(jié)束語
本文中,我們了解了Jakarta Commons Lang組件的一些主要功能??偟恼f來,Commons項(xiàng)目是非常有用的項(xiàng)目,但并沒有得到充分利用。雖然開源項(xiàng)目使用了許多Commons組件,但其在開源世界之外的應(yīng)用并不十分廣泛?,F(xiàn)在您已經(jīng)對(duì)Lang的功能有所了解,應(yīng)該考慮立即將其應(yīng)用到您的應(yīng)用程序中。另外,還可以在Commons項(xiàng)目中尋找各種有用的組件,從而簡(jiǎn)化XML解析、使應(yīng)用程序進(jìn)行HTTP會(huì)話、實(shí)現(xiàn)系統(tǒng)化驗(yàn)證以及執(zhí)行很多其他功能。
下載
下載本文中用到的代碼:examples.zip (3KB)
參考資料
Harshad Oak是Java J2EE門戶網(wǎng)站IndicThreads.com的創(chuàng)始人。他編寫了Pro Jakarta Commons和Oracle JDeveloper 10g:Empowering J2EE Development,并與人合著了Java 2 Enterprise Edition 1.4 Bible。他還是Rightrix Solutions的創(chuàng)始人。
聯(lián)系客服