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

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