`

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解惑_solve65p_

    《Java解惑(中文版)》是一本专为Java初学者设计的学习资料,旨在帮助读者解答在学习Java过程中遇到的各种困惑。"solve65p"可能代表这本书包含65个问题或主题,每个都深入浅出地进行了讲解,旨在解决初学者在编程...

    Java PUZZLE Java 解惑

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

    JAVA 解惑 java经典

    2. **面向对象编程**:Java是一种面向对象的语言,封装、继承、多态是其三大特性。封装涉及如何隐藏内部实现细节,提供公共接口;继承允许类间共享代码,提高代码复用;多态则增强了程序的灵活性。 3. **异常处理**...

    Java解惑 中文版

    《Java解惑中文版》是一本专为Java程序员设计的指南,旨在帮助读者解决在编程过程中遇到的各种问题,提升程序的健壮性。本书深入浅出地探讨了Java语言的核心概念、常见疑惑以及最佳实践,旨在使开发者能够编写出更...

    Java解惑.pdf

    这份“Java解惑.pdf”文档很可能包含了解决Java开发者在编程过程中遇到的常见问题和困惑的详细解答。以下是可能涵盖的一些Java相关知识点: 1. **基础语法**:Java的基础语法包括变量、数据类型、运算符、流程控制...

    "java解惑" PDF版本

    "java解惑" PDF版本

    java解惑 PDF版

    文档《java解惑 PDF版》中列举了95个这样的谜题,每个谜题都旨在帮助开发者理解并纠正一些常见的错误理解。以下是根据提供的部分内容解析的几个相关知识点。 ### 表达式谜题与取余操作符(%)的行为 在Java中,...

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

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

    JAVA解惑.pdf

    《JAVA解惑》这本书主要针对Java编程中遇到的各种常见问题和困惑进行了解答,旨在帮助开发者深入理解Java语言,提高编程技巧。以下是一些关键的知识点解析: 1. **异常处理**:Java中的异常处理是通过try-catch-...

    java解惑java解惑java解惑

    - **封装、继承和多态**:这三个面向对象的特性是理解Java程序设计的关键。 - **访问修饰符**:public、private、protected和默认,它们控制了类成员的可见性。 3. **异常处理** - **try-catch-finally**:Java...

    4,JAVA解惑 高清PDF 下载

    《JAVA解惑》是Java开发者领域的一本经典著作,它被广大...总之,《JAVA解惑》是一本涵盖了Java核心知识点、实战技巧和高级特性的宝典,无论你是Java新手还是老手,都能从中受益匪浅,解决你在Java编程中的种种疑惑。

    java解惑 for all javaer

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

    JAVA解惑.pfd

    JAVA解惑

    java解惑(包括pdf和答案)

    "java解惑"这个主题旨在帮助初学者理解和解决在学习Java过程中遇到的问题,通过实例来深入浅出地讲解Java的基础知识,同时也强调了实用技巧和注意事项。 "Java解惑"的资料可能包含了两部分:`.chm`和`.pdf`格式的...

    Java解惑(中文).pdf

    《Java解惑(中文)》是一本专门为Java开发者编写的指南书籍,旨在解决在实际编程过程中遇到的各种疑惑和难题。本书以中文语言呈现,使得国内的Java程序员能够更轻松地理解并应用其中的知识。通过阅读这本书,读者...

    Java解惑Java解惑

    《Java解惑》系列是一本专注于解答Java编程中常见困惑的书籍,由作者junJZ_2008在JavaEye社区分享。该系列共有八篇文章,内容涵盖了许多基础但重要的Java知识点,旨在帮助读者深化对Java语言的理解,尤其是那些在...

Global site tag (gtag.js) - Google Analytics