`

java解惑你知多少(三)

    博客分类:
  • Java
 
阅读更多

17. 不要使用基于减法的比较器

Java代码  收藏代码
  1. Comparator<Integer> c = new Comparator<Integer>() {  
  2.  public int compare(Integer i1, Integer i2) {  
  3.   return i1 - i2;// 升序  
  4.  }  
  5. };  
  6. List<Integer> l = new ArrayList<Integer>();  
  7. l.add(new Integer(-2000000000));  
  8. l.add(new Integer(2000000000));  
  9. Collections.sort(l, c);  
  10. System.out.println(l);// [2000000000, -2000000000]  

上面程序的比较器是升序,结果却不是这样,比较时出现了什么问题?

 

先看看下面程序片断:

Java代码  收藏代码
  1. int x = -2000000000;  
  2. int y = 2000000000;  
  3. /* 
  4.  * -2000000000 即 -(01110111001101011001010000000000) 
  5.  * 的补码为:                10001000110010100110110000000000 
  6.  *  
  7.  * 计算过程使用竖式表示: 
  8.  * 10001000110010100110110000000000 
  9.  * 10001000110010100110110000000000 
  10.  * -------------------------------- 
  11.  * 00010001100101001101100000000000 
  12.  *  
  13.  * 计算结果溢出,结果为294967296 
  14.  */  
  15. System.out.println(x - y);// 294967296  

所以不要使用减法的比较器,除非能确保要比较的数值之间的距离永远不会大于Intger. MAX_VALUE。

 

基于整型的比较器的实现一般使用如下的方式来比较:

Java代码  收藏代码
  1. public int compare(Integer i1, Integer i2) {  
  2.  return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));  
  3. }  

 
18.  int i=-2147483648与int i=-(2147483648)?

Java代码  收藏代码
  1. int i=-(2147483648);  

编译通不过!为什么

 

int字面常量2147483638只能作为一元负操作符的操作数来使用。

 

类似的还有最大long:

Java代码  收藏代码
  1. long i=–(9223372036854775808L);  

 
字符串

19. char类型相加

Java代码  收藏代码
  1. 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转义字符

Java代码  收藏代码
  1. //\u0022是双引号的Unicode编码表示  
  2. 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上的行结束标示符

Java代码  收藏代码
  1. String line = (String)System.getProperties().get("line.separator");  
  2. for(int i =0; i < line.length();i++){  
  3.  System.out.println((int)line.charAt(i));  
  4. }  

在Windows上运行结果:
13
10

在Linux上运行的结果:
10

在Windows平台上,行分隔符是由回车(\r)和紧其后的换行(\n)组成,但在Unix平台上通常使用单独的换行(\n)

表示。


23. 输出0-255之间的ISO8859-1符

Java代码  收藏代码
  1. byte bts[] = new byte[256];  
  2. for (int i = 0; i < 256; i++) {  
  3.  bts[i] = (byte) i;  
  4. }  
  5. // String str = new String(bts,"ISO8859-1");//正确的做法  
  6. String str = new String(bts);//使用操作系统默认编码方式编码(XP GBK)  
  7. for (int i = 0, n = str.length(); i < n; i++) {  
  8.  System.out.print((int) str.charAt(i) + " ");  
  9. }  

上面不会输出0-255之间的数字串,正确的方式要使用new String(bts," ISO8859-1") 方式来解码。

 

ISO8859-1是唯一能够让该程序按顺序打印从0到255的整数的缺少字符集,这也是唯一在字符和字节之间一对一的映射

字符集。

 

通过java获取操作系统的默认编码方式:

Java代码  收藏代码
  1. System.getProperty("file.encoding");//jdk1.4或之前版本  
  2. java.nio.charset.Charset.defaultCharset();//jdk1.5或之后版本  

 
24. String的replace()与replaceAll()

Java代码  收藏代码
  1. System.out.println(".".replaceAll(".class""\\$"));  

上面程序将 . 替换成 \$,但运行时报异常,主要原replaceAll的第二参数有两个字符(\ $)是特殊字符,具有特殊

意思(\用来转移 \ 与 $,$后面接数字表示反向引用)。另外,replaceAll的第一参数是正则表达式,所以要注意特

殊字符,正确的作法有以下三种:

Java代码  收藏代码
  1. System.out.println(".class".replaceAll("\\.""\\\\\\$"));  
  2. System.out.println(".class".replaceAll("\\Q.\\E""\\\\\\$"));  
  3. 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)方法却不使用正则式,但它们只支持字符,而不是字符串,使用起来

受限制:

Java代码  收藏代码
  1. System.out.println(".".replace('.','\\'));//能将 . 替换成 \  
  2. System.out.println(".".replace('.','$')); //能将 . 替换成 $  

 
25. 一段程序的三个Bug

Java代码  收藏代码
  1. Random rnd = new Random();  
  2. StringBuffer word = null;  
  3. switch (rnd.nextInt(2)) {  
  4. case 1:  
  5.  word = new StringBuffer('P');  
  6. case 2:  
  7.  word = new StringBuffer('G');  
  8. default:  
  9.  word = new StringBuffer('M');  
  10. }  
  11. word.append('a');  
  12. word.append('i');  
  13. word.append('n');  
  14. 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的初始容量了,而不是字符本身。

 

以下是修改后的程序片段:

Java代码  收藏代码
  1. Random rnd = new Random();  
  2. StringBuffer word = null;  
  3. switch (rnd.nextInt(3)) {  
  4. case 1:  
  5.  word = new StringBuffer("P");  
  6.  break;  
  7. case 2:  
  8.  word = new StringBuffer("G");  
  9.  break;  
  10. default:  
  11.  word = new StringBuffer("M");  
  12.  break;// 可以不要  
  13.   
  14. }  
  15. word.append('a');  
  16. word.append('i');  
  17. word.append('n');  
  18. System.out.println(word);  
分享到:
评论

相关推荐

    java解惑(+Java 解惑你知多少)

    你认为自己了解Java多少?你是个爱琢磨的代码侦探吗?你是否曾经花费数天时间去追踪一个由Java或其类库的陷阱和缺陷而导致的bug?你喜欢智力测验吗?本书正好适合你!.. Bloch和Gafter继承了Effective Jaya一书的传统,...

    java解惑java解惑java解惑

    java解惑java解惑java解惑java解惑java解惑java解惑

    Java解惑Java解惑

    Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑

    Java解惑.pdf

    Java解惑.pdf Java解惑.pdf Java解惑.pdf Java解惑.pdf

    JAVA 解惑 java经典

    JAVA解惑,你面包括一些java经典的问题。

    Java解惑 中文版

    Java解惑中文版 Java解惑 java健壮程序

    JAVA解惑.pdf

    JAVA解惑.pdf JAVA解惑.pdf JAVA解惑.pdf

    Java PUZZLE Java 解惑

    Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑

    最新版的Java-解惑

    《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》

    Java解惑(中文版)_java_java解惑_solve65p_

    与java相关的的学习,适合初学者,可以看看

    Java解惑 布洛克 著;陈昊鹏 译

    《Java解惑》 布洛克 著;陈昊鹏 译 扫描清晰带目录,仅供参阅,请支持正版

    "java解惑" PDF版本

    "java解惑" PDF版本

    java解惑 for all javaer

    讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java程序员阅读。

    Java解惑

    Java解惑,罗列你意想不到的100道java疑惑

    JAVA解惑(JAVA谜题) 中文版(PDF)

    Java解惑,是一本以大量java实例,讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java...

    Java解惑(中文).pdf

    Java解惑(中文).pdf 给大家介绍java中容易迷惑用错的实例

    4,JAVA解惑 高清PDF 下载

    Java四大名著之一:4,JAVA解惑 高清PDF 下载

    《Java Pazzlers》Java解惑.pdf 书签齐全

    该书特写了95个有关Java或其类库的陷阱和缺陷的谜题,其中大多数谜题都采用了短程序的方式,这些程序的行为与其看似的大相径庭。在每个谜题之后都给出了详细的解惑方案,这些解惑方案超越了对程序行为的简单解释,向...

    java解惑中文版

    java解惑中文版 这本书吊的不行不行的 看完这本书你对java的理解能上一个档次

Global site tag (gtag.js) - Google Analytics