17.?不要使用基于減法的比較器
- Comparator<Integer>?c?=? new ?Comparator<Integer>()?{??
- ? public ? int ?compare(Integer?i1,?Integer?i2)?{??
- ?? return ?i1?-?i2; //?升序 ??
- ?}??
- };??
- List<Integer>?l?=? new ?ArrayList<Integer>();??
- l.add( new ?Integer(- 2000000000 ));??
- l.add( new ?Integer( 2000000000 ));??
- Collections.sort(l,?c);??
- System.out.println(l); //?[2000000000,?-2000000000] ??
上面程序的比較器是升序,結(jié)果卻不是這樣,比較時(shí)出現(xiàn)了什么問題?
?
先看看下面程序片斷:
- int ?x?=?- 2000000000 ;??
- int ?y?=? 2000000000 ;??
- /* ?
- ?*?-2000000000?即?-(01110111001101011001010000000000) ?
- ?*?的補(bǔ)碼為:????????????????10001000110010100110110000000000 ?
- ?*? ?
- ?*?計(jì)算過程使用豎式表示: ?
- ?*?10001000110010100110110000000000 ?
- ?*?10001000110010100110110000000000 ?
- ?*?-------------------------------- ?
- ?*?00010001100101001101100000000000 ?
- ?*? ?
- ?*?計(jì)算結(jié)果溢出,結(jié)果為294967296 ?
- ?*/ ??
- System.out.println(x?-?y); //?294967296 ??
所以不要使用減法的比較器,除非能確保要比較的數(shù)值之間的距離永遠(yuǎn)不會(huì)大于Intger. MAX_VALUE。
?
基于整型的比較器的實(shí)現(xiàn)一般使用如下的方式來比較:
- public ? int ?compare(Integer?i1,?Integer?i2)?{??
- ? return ?(i1?<?i2???- 1 ?:?(i1?==?i2??? 0 ?:? 1 ));??
- }??
?
18.? int i=-2147483648與int i=-(2147483648)?
- int ?i=-( 2147483648 );??
編譯通不過!為什么
?
int字面常量2147483638只能作為一元負(fù)操作符的操作數(shù)來使用。
?
類似的還有最大long:
- long ?i=–(9223372036854775808L);??
?
字符串
19.?char類型相加
- System.out.println( 'a' ?+? 'A' ); //162 ??
上面的結(jié)果不是 aA ,而是 162。
當(dāng)且僅當(dāng)+操作符的操作數(shù)中至少有一個(gè)是String類型時(shí),才會(huì)執(zhí)行字符串連接操作;否則,執(zhí)行加法。如果要連接的
數(shù)值沒有一個(gè)是字符串類型的,那么你可以有幾種選擇:預(yù)置一個(gè)空字符串("" + 'a' + 'A');將第一個(gè)數(shù)值用
String.valueOf()顯示地轉(zhuǎn)換成一個(gè)字符串(String.valueOf('a') + 'A');使用一個(gè)字符串緩沖區(qū)(sb.append
('a');sb.append('A'););或者如果使用的是JDK5.0,可以用printf(System.out.printf("%c%c",'a','A'));
20.?程序中的Unicode轉(zhuǎn)義字符
- //\u0022是雙引號(hào)的Unicode編碼表示 ??
- System.out.println( "a\u0022.length()?+?\u0022b" .length()); //?2 ??
Unicode編碼表示的字符是在編譯期間就轉(zhuǎn)換成了普通字符,它與普通轉(zhuǎn)義字符(如:\")是不一樣的,它們是在程序
被解析為各種符號(hào)之后才處理轉(zhuǎn)義字符序列。
?
21.?注釋中的Unicode轉(zhuǎn)義字符
如果程序中含有以下的注釋:// d:\a\b\util ,程序?qū)⒉荒芫幾g通過,原因是\u后面跟的不是四個(gè)十六進(jìn)制數(shù)字,但
編譯器在編譯時(shí)卻要把\u開頭的字符的字符看作是Unicode編碼表示的字符。
?
所以要注意:注釋中也是支持Unicode轉(zhuǎn)義字符的。
?
另外一個(gè)問題是不能在注釋行的中間含有 \u000A 表示換行的Unicode字符,因?yàn)檫@樣在編譯時(shí)讀到 \u000A 時(shí),表示
行結(jié)束,那么后面的字符就會(huì)當(dāng)作程序代碼而不在是注釋了。
22.?Windows與Linux上的行結(jié)束標(biāo)示符
- String?line?=?(String)System.getProperties().get( "line.separator" );??
- for ( int ?i?= 0 ;?i?<?line.length();i++){??
- ?System.out.println(( int )line.charAt(i));??
- }??
在Windows上運(yùn)行結(jié)果:
13
10
在Linux上運(yùn)行的結(jié)果:
10
在Windows平臺(tái)上,行分隔符是由回車(\r)和緊其后的換行(\n)組成,但在Unix平臺(tái)上通常使用單獨(dú)的換行(\n)
表示。
23.?輸出0-255之間的ISO8859-1符
- byte ?bts[]?=? new ? byte [ 256 ];??
- for ?( int ?i?=? 0 ;?i?<? 256 ;?i++)?{??
- ?bts[i]?=?( byte )?i;??
- }??
- //?String?str?=?new?String(bts,"ISO8859-1");//正確的做法 ??
- String?str?=? new ?String(bts); //使用操作系統(tǒng)默認(rèn)編碼方式編碼(XP?GBK) ??
- for ?( int ?i?=? 0 ,?n?=?str.length();?i?<?n;?i++)?{??
- ?System.out.print(( int )?str.charAt(i)?+? "?" );??
- }??
上面不會(huì)輸出0-255之間的數(shù)字串,正確的方式要使用new String(bts," ISO8859-1") 方式來解碼。
?
ISO8859-1是唯一能夠讓該程序按順序打印從0到255的整數(shù)的缺少字符集,這也是唯一在字符和字節(jié)之間一對一的映射
字符集。
?
通過java獲取操作系統(tǒng)的默認(rèn)編碼方式:
- System.getProperty( "file.encoding" ); //jdk1.4或之前版本 ??
- java.nio.charset.Charset.defaultCharset(); //jdk1.5或之后版本 ??
?
24.?String的replace()與replaceAll()
- System.out.println( "." .replaceAll( ".class" ,? "\\$" ));??
上面程序?qū)?. 替換成 \$,但運(yùn)行時(shí)報(bào)異常,主要原replaceAll的第二參數(shù)有兩個(gè)字符(\ $)是特殊字符,具有特殊
意思(\用來轉(zhuǎn)移 \ 與 $,$后面接數(shù)字表示反向引用)。另外,replaceAll的第一參數(shù)是正則表達(dá)式,所以要注意特
殊字符,正確的作法有以下三種:
- System.out.println( ".class" .replaceAll( "\\." ,? "\\\\\\$" ));??
- System.out.println( ".class" .replaceAll( "\\Q.\\E" ,? "\\\\\\$" ));??
- System.out.println( ".class" .replaceAll(Pattern.quote( "." ),?Matcher.quoteReplacement( "\\$" )));??
API對\、\Q與\E的解釋:
?
\? 引用(轉(zhuǎn)義)下一個(gè)字符
?
\Q引用所有字符,直到 \E
?
\E結(jié)束從 \Q 開始的引用
?
JDK5.0新增了一些解決此問題的新方法:
java.util.regex.Pattern.quote(String s):使用\Q與\E將參數(shù)引起來,這些被引用的字符串就是一般的字符,哪怕
含有正則式特殊字符。
java.util.regex.Matcher.quoteReplacement(String s):將\與$轉(zhuǎn)換成能應(yīng)用于replaceAll第二個(gè)參數(shù)的字符串,
即可作為替換內(nèi)容。
String的replace(char oldChar, char newChar)方法卻不使用正則式,但它們只支持字符,而不是字符串,使用起來
受限制:
- System.out.println( "." .replace( '.' , '\\' )); //能將?.?替換成?\ ??
- System.out.println( "." .replace( '.' , '$' ));? //能將?.?替換成?$ ??
?
25.?一段程序的三個(gè)Bug
- Random?rnd?=? new ?Random();??
- StringBuffer?word?=? null ;??
- switch ?(rnd.nextInt( 2 ))?{??
- case ? 1 :??
- ?word?=? new ?StringBuffer( 'P' );??
- case ? 2 :??
- ?word?=? new ?StringBuffer( 'G' );??
- default :??
- ?word?=? new ?StringBuffer( 'M' );??
- }??
- word.append( 'a' );??
- word.append( 'i' );??
- word.append( 'n' );??
- System.out.println(word);??
上面的程序目的是等概率的打印 Pain、Gain、Main 三個(gè)單詞,但多次運(yùn)行程序卻發(fā)現(xiàn)永遠(yuǎn)只會(huì)打印 ain,這是為什
么?
?
第一個(gè)問題在于:rnd.nextInt(2)只會(huì)返回0、1 兩個(gè)數(shù)字,所以上面只會(huì)走case 1: 的分支語句,case 2: 按理是永
遠(yuǎn)不會(huì)走的。
第二個(gè)問題在于:如果case語句不以break結(jié)束時(shí),則一直會(huì)往向運(yùn)行,即直到執(zhí)行到break的case語句止,所以上面
的的語句每次都會(huì)執(zhí)行default分支語句。
第三個(gè)問題在于:StringBuffer的構(gòu)造函數(shù)有兩種可接受參數(shù)的,一個(gè)是StringBuffer(int capacity)、另一個(gè)是
StringBuffer(String str),上面用的是StringBuffer(char)構(gòu)造函數(shù),實(shí)質(zhì)上運(yùn)行時(shí)將字符型轉(zhuǎn)換成了int型,這樣
將字符當(dāng)作StringBuffer的初始容量了,而不是字符本身。
?
以下是修改后的程序片段:
- Random?rnd?=? new ?Random();??
- StringBuffer?word?=? null ;??
- switch ?(rnd.nextInt( 3 ))?{??
- case ? 1 :??
- ?word?=? new ?StringBuffer( "P" );??
- ? break ;??
- case ? 2 :??
- ?word?=? new ?StringBuffer( "G" );??
- ? break ;??
- default :??
- ?word?=? new ?StringBuffer( "M" );??
- ? break ; //?可以不要 ??
- ??
- }??
- word.append( 'a' );??
- word.append( 'i' );??
- word.append( 'n' );??
- System.out.println(word);??
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
