1.不可變String
String 對(duì)象是不可變的。String類(lèi)中每一個(gè)看起來(lái)會(huì)修改String值的方法枕赵, 實(shí)際上都是創(chuàng)建了一個(gè)全新的String對(duì)象君纫, 以包含修改后的字符串內(nèi)容性昭。而最初的String對(duì)象則絲亳未動(dòng)涤躲。
對(duì)千一個(gè)方法而言报嵌, 參數(shù)是為該方法提供信息的虱咧, 而不是想讓該方法改變自己的。
2.重載+與StringBuilder
用千String的"+"與"+=" 是Java中僅有的兩個(gè)重載過(guò)的操作符锚国,而Java井不允許程序員重載任何操作符腕巡。
如果拿不準(zhǔn)該用哪種方式,隨時(shí)可以用javap來(lái)分析你的程序血筑。
StringBuilder是JavaSE5引人的绘沉,在這之前Java用的是StringBuffer。后者是線程安全的豺总,因此開(kāi)銷(xiāo)也會(huì)大些车伞,所以在JavaSE5/6中,字符串操作應(yīng)該還會(huì)更快一點(diǎn)园欣。
3.無(wú)意識(shí)的遞歸
Java中的每個(gè)類(lèi)從根本上都是繼承自O(shè)bject,標(biāo)準(zhǔn)容器類(lèi)自然也不例外帖世。因此容器類(lèi)都有 toString()方法,并且覆寫(xiě)了該方法沸枯,使得它生成的String結(jié)果能夠表達(dá)容器自身日矫,以及容器所 包含的對(duì)象。
public class InfiniteRecursion {
public String toString() {
return " InfiniteRecursion address: " + this + "\n":
}
這里發(fā)生了自動(dòng)類(lèi)型轉(zhuǎn)換绑榴,由InfiniteRecursion類(lèi)型轉(zhuǎn)換成String類(lèi)型哪轿。因?yàn)榫幾g器看到一個(gè)String對(duì)象后面跟著一個(gè)"+"'而再后面的對(duì)象不是String,于是編譯器試渚將this轉(zhuǎn)換成一個(gè)String。它怎么轉(zhuǎn)換呢翔怎,正是通過(guò)調(diào)用this上的toString()方法窃诉,千是就發(fā)生了遞歸調(diào)用。
如果你真的想要打印出對(duì)象的內(nèi)存地址赤套,應(yīng)該調(diào)用Object.toString()方法飘痛,這才是負(fù)責(zé)此任務(wù)的方法。所以容握,你不該使用this,而是應(yīng)該調(diào)用super.toString()方法宣脉。
4.String上的操作
當(dāng)需要改變字符串的內(nèi)容時(shí),String類(lèi)的方法都會(huì)返回一個(gè)新的 String對(duì)象剔氏。同時(shí)塑猖,如果內(nèi)容沒(méi)有發(fā)生改變,String的方法只是返回指向原對(duì)象的引用而已谈跛。這 可以節(jié)約存儲(chǔ)空間以及避免額外的開(kāi)銷(xiāo)羊苟。
5.格式化輸出
5.1 printf()
5.2 System.out.format()
format()與printf()是等價(jià)的残制。
5.3 Formatter類(lèi)
在Java中券腔,所有新的格式化功能都由java.util.Formatter類(lèi)處理刹孔。可以將Formatte看作一個(gè)翻譯器倔幼,它將你的格式化字符串與數(shù)據(jù)翻譯成需要的結(jié)果鸯匹。當(dāng)你創(chuàng)建一個(gè)Formatter對(duì)象的時(shí)候匾灶, 需要向其構(gòu)造器傳遞一些信息吆豹,告訴它最終的結(jié)果將向哪里輸出。
5.4 格式化說(shuō)明符
%[argument_index$] [flags] [width][.precision]conversion
最常見(jiàn)的應(yīng)用是控制一個(gè)域的最小尺寸占遥,這可以通過(guò)指定width來(lái)實(shí)現(xiàn)俯抖。 Formatter對(duì)象 通過(guò)在必要時(shí)添加空格,來(lái)確保一個(gè)域至少達(dá)到某個(gè)長(zhǎng)度瓦胎。 在默認(rèn)的情況下芬萍,數(shù)據(jù)是右對(duì)齊,不過(guò)可以通過(guò)使用"-"標(biāo)志來(lái)改變對(duì)齊方向搔啊。
與width相對(duì)的是precision, 它用來(lái)指明最大尺寸柬祠。width可以應(yīng)用于各種類(lèi)型的數(shù)據(jù)轉(zhuǎn)換, 并且其行為方式都一樣负芋。 precision則不然漫蛔, 不是所有類(lèi)型的數(shù)據(jù)都能使用precision, 而且,應(yīng)用于不同類(lèi)型的數(shù)據(jù)轉(zhuǎn)換時(shí)旧蛾,precision的意義也不同莽龟。 在將precision應(yīng)用于String時(shí),它表示打印 String時(shí)輸出字符的最大數(shù)址锨天。 而在將precision應(yīng)用千浮點(diǎn)數(shù)時(shí)毯盈, 它表示小數(shù)部分要顯示出來(lái)的位數(shù)(默認(rèn)是6位小數(shù)), 如果小數(shù)位數(shù)過(guò)多則舍人病袄, 太少則在尾部補(bǔ)零搂赋。 由千整數(shù)沒(méi)有小數(shù)部分,所以precision無(wú)法應(yīng)用千整數(shù)益缠,如果你對(duì)整數(shù)應(yīng)用precision, 則會(huì)觸發(fā)異常脑奠。
5.5 Formatter轉(zhuǎn)換
5.6 String.format()
String.format()是一個(gè) static方法,它接受與Formatter.format()方法一樣的參數(shù)幅慌,但返回一個(gè)String對(duì)象宋欺。當(dāng)你只需使回用format()方法一次的時(shí)候,String.format()用起來(lái)很方便欠痴。
其實(shí)在String.format()內(nèi)部迄靠,它也是創(chuàng)建一個(gè)Formatter對(duì)象秒咨,然后將你傳人的參數(shù)轉(zhuǎn)給該Formatter喇辽。
6.正則表達(dá)式
正則表達(dá)式提供了一種完全通用的方式,能夠解決各種字符串處理相關(guān)的問(wèn)題:匹配雨席、選擇菩咨、編輯以及驗(yàn)證。
6.1 基礎(chǔ)
在Java中,\的意思是“我要插人一個(gè)正則表達(dá)式的反斜線抽米,所以其后的字符具有特殊的意義特占。例如,如果你想表示一位數(shù)字云茸,那么正則表達(dá)式應(yīng)該是\d是目。如果你想插人一個(gè)普通的反斜線,則應(yīng)該這樣\\标捺。不過(guò)換行和制表符之類(lèi)的東西只需使用單反斜線:\n\t懊纳。
在正則表達(dá)式中,括號(hào)有著將表達(dá)式分組的效果亡容,而豎直線|則表示或操作嗤疯。
String類(lèi)還自帶了一個(gè)非常有用的正則表達(dá)式工具--split()方法,其功能是“將字符串從正則表達(dá)式匹配的地方切開(kāi)闺兢∶浚”
6.2 創(chuàng)建正則表達(dá)式
完整請(qǐng)參考java.util.regex.Pattern
6.3 量詞
量詞描述了一個(gè)模式吸收輸入文本的方式:
- 貪婪型:量詞總是貪婪的,除非有其他的選項(xiàng)被設(shè)置屋谭。 貪婪表達(dá)式會(huì)為所有可能的模式發(fā)現(xiàn)盡可能多的匹配脚囊。 導(dǎo)致此問(wèn)題的一個(gè)典型理由就是假定我們的模式僅能匹配第一個(gè)可能的字符組,如果它是貪婪的戴而,那么它就會(huì)繼續(xù)往下匹配凑术。
- 勉強(qiáng)型:用問(wèn)號(hào)來(lái)指定, 這個(gè)址詞匹配滿足模式所需的最少字符數(shù)所意。 因此也稱(chēng)作懶惰的淮逊、 最少匹配的、 非貪婪的扶踊、 或不貪婪的泄鹏。
- 占有型:目前, 這種類(lèi)型的懋詞只有在Java語(yǔ)言中才可用(在其他語(yǔ)言中不可用)秧耗,井且也更高級(jí)备籽,因此我們大概不會(huì)立刻用到它。 當(dāng)正則表達(dá)式被應(yīng)用于字符串時(shí)分井,它會(huì)產(chǎn)生相當(dāng)多的狀態(tài)车猬, 以便在匹配失敗時(shí)可以回溯。 而 “占有的“ 址詞并不保存這些中間狀態(tài)尺锚, 因此它們可以防止回溯珠闰。 它們常常用千防止正則表達(dá)式失控,因此可以使正則表達(dá)式執(zhí)行起來(lái)更有效瘫辩。
多數(shù)正則表達(dá)式操作都接受CharSequence類(lèi)型的參數(shù)伏嗜。
6.4 Pattern和Matcher
一般來(lái)說(shuō)坛悉,比起功能有限的String類(lèi),我們更愿意構(gòu)造功能強(qiáng)大的正則表達(dá)式對(duì)象承绸。只需導(dǎo)人Java.util.regex包裸影,然后用staticPattern.compile()方法來(lái)編譯你的正則表達(dá)式即可。它會(huì)根據(jù)你的String類(lèi)型的正則表達(dá)式生成一個(gè)Pattern對(duì)象军熏。接下來(lái)轩猩,把你想要檢索的字符串傳人 Pattern對(duì)象的matcher()方法。matcher()方法會(huì)生成一個(gè)Matcher對(duì)象荡澎,它有很多功能可用界轩。
Matcher
組(Groups)
組是用括號(hào)劃分的正則表達(dá)式,可以根據(jù)組的編號(hào)來(lái)引用某個(gè)組衔瓮。組號(hào)為0表示整個(gè)表達(dá)式浊猾, 組號(hào)1表示被第一對(duì)括號(hào)括起的組, 依此類(lèi)推热鞍。
6.5 split()
split()方法將輸入字符串?dāng)嚅_(kāi)成字符串對(duì)象數(shù)組葫慎。
6.6 替換操作
正則表達(dá)式特別便千替換文本,它提供了許多方法:replaceFirst(String replacement)以參 數(shù)字符串replacemen氓換掉第一個(gè)匹配成功的部分薇宠。replaceAll(Stringreplacement)以參數(shù)字符串replacement替換所有匹配成功的部分偷办。appendReplacement(StringBuffersbuf, String replacement)執(zhí)行漸進(jìn)式的替換,而不是像replaceFirst()和replaceAII()那樣只替換第一個(gè)匹配或全部匹配澄港。
6.7 reset()
通過(guò)reset()方法椒涯,可以將現(xiàn)有的Matcher對(duì)象應(yīng)用千一個(gè)新的字符序列。
6.8 正則表達(dá)式與Java I/O
7.掃描輸入
到目前為止回梧,從文件或標(biāo)準(zhǔn)輸人讀取數(shù)據(jù)還是一件相當(dāng)痛苦的事情废岂。一般的解決之道就是讀入讀入一行文本,對(duì)其進(jìn)行分詞狱意,然后使用Integer湖苞、Double等類(lèi)的各種解析方法來(lái)解析數(shù)據(jù)。
Java SE5新增了Scanner類(lèi)详囤, 它可以大大減輕掃描輸入的工作負(fù)擔(dān)财骨。
7.1 Scanner定界符
默認(rèn)是空白字符,但是可以通過(guò)正則表達(dá)式指定自己所需的定界符藏姐。
7.2 用正則表達(dá)式掃描
除了能夠掃描基本類(lèi)型之外隆箩,你還可以使用自定義的正則表達(dá)式進(jìn)行掃描,這在掃描復(fù)雜數(shù)據(jù)的時(shí)候非常有用羔杨。
8.StringTokenizer
在Java引入正則表達(dá)式和Scanner類(lèi)之前捌臊,分割字符串的唯一方法是使用StringTokenizer來(lái)分詞。 不過(guò)问畅,現(xiàn)在有了正則表達(dá)式和Scanner, 我們可以使用更加簡(jiǎn)單娃属、更加簡(jiǎn)潔的方式來(lái)完成同樣的工作了。