PIT 06:域和流
下面的代码是一个文件拷贝的方法,设计的是即便抛出异常也会关闭流:
public static void pit06(String src,String dest) throws IOException { InputStream in = null; OutputStream out = null; try { in = new FileInputStream(src); out = new FileOutputStream(dest); byte[] buf = new byte[1024]; int n; while((n=in.read(buf))>0) { out.write(buf,0,n); } } catch(Exception e) { e.printStackTrace(); } finally { if(in!=null) { in.close(); } if(out!=null) { out.close(); } } }这个程序看起来已经面面俱到了,不过可惜的是,finally块里,当close方法异常时,还是会无法关闭流,即close的调用可能会导致finally代码块异常结束,解决的方法也很简单,把close的调用放到嵌套在try catch块里即可:
} finally { try { if(in!=null) { in.close(); } } catch(Exception ex) { ex.printStackTrace(); } try { if(out!=null) { out.close(); } } catch(Exception ex) { ex.printStackTrace(); } }PIT 07:有毒的括号
众所周知,Integer.MAX_VALUE的值是2147483647,Integer.MIN_VALUE的值是-2147483648,但如果这样写:
public static void pit07() { int i = -(2147483648); }这里编译肯定会报错,程序会先计算括号里的内容,报超出int范围,所以你的业务代码里加括号的内容一定要捋清楚,防止踩坑。
PIT 08:三元表达式
你会怎么理解这段代码呢:
public static void pit08() { char x = 'X'; int i = 0; System.out.println(true?x:0); System.out.println(true?x:i); }毫无疑问这里两次输出的都是变量x的值,但并不是XX,而是X88。
这里可以从条件表达式结果类型的规则来找原因,对于表达式的第二个和第三个操作数的类型判断,其中有这么三条规则:
1.如果这两个操作数具有相同的类型,那么它就是条件表达式的类型;
2.如果一个操作数的类型是T(byte、short、char),而另一个操作数是一个int类型的常量表达式,它的值可以用T来表示,那么条件表达式的类型就是T;
3. 否则,将对操作数的类型进行二进制数字提升,而条件表达式的类型就是提升后的类型。
第一个输出语句满足第二条,所以输出X,第二个输出语句满足第三条,对char和int进行二进制数字提升之后,就是int,输出X的Unicode码88。
PIT 09:转义字符与Unicode
当转义字符遇到Unicode,简直不要再崩溃:
/** * from D:\Test\units\Test01.java */ public static void pit09() { System.out.println("Hello Word!"); }很简单的一个输出语句,却连编译都通不过,问题就出在注释里,\u是Unicode码的开始,即便它在注释里,编译器依旧不会放过它,可想而知,代码里如果有类似现象,写不清楚的Unicode,该是多么崩溃。
PIT 10:i==-i
正常来说,满足i==-i的整数数值只有0,但在程序里,还有两个数,那就是Integer.MIN_VALUE和Integer.MAX_VALUE,这是因为-运算符是对数值进行二进制补码运算的,即取反加一,而这两个数补码运算后,它的低32位等于它本身,虽然高位溢出了,但会被Java忽略,故而依旧满足上述表达式。如果你的程序中有该判断逻辑,那就要小心了。
精彩待续。。。
相关阅读:Java雷坑整理(1)