java技巧

1、

如果你正在在一个性能临界(performance-critical)环境中使用isOdd 方法,那么用位操作符AND(&)来替代取余操作符会显得更好:

public static boolean isOdd(int i){
       return (i & 1) != 0;
}
2、

浮点运算在一个范围很广的值域上提供了很好的近似,但是它通常不能产生精确的结果。二进制浮点对于货币计算是非常不适合的,因为它不可能将0.1——或者10的其它任何次负幂——精确表示为一个长度有限的二进制小数。

解决该问题的一种方式是使用某种整数类型,例如int 或long。另一种方式是使用执行精确小数运算的BigDecimal。

3、

final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
虽然计算结果是long类型,但是乘法过程的int已经溢出。
更改:

final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;

4、

如果十六进制和八进制字面常量的最高位被置位了,那么它们就是负数。

因为byte 是一个有符号类型,而char是一个无符号类型。从byte 到char 的转换被认为不是一个拓宽原始类型的转换,而是一个拓宽并窄化原始类型的转换:如果最初的数值类型是有符号的,那么就执行符号扩展;如果它是char,那么不管它将要被转换成什么类型,都执行零扩展。

如果你在将一个char 数值c 转型为一个宽度更宽的类型,并且你不希望有符号扩展,那么为清晰表达意图,可以考虑使用一个位掩码,即使它并不是必需的:

int i = c & 0xffff;
如果你在将一个char 数值c 转型为一个宽度更宽的整型,并且你希望有符号扩展,那么就先将char 转型为一个short,它与char 具有同样的宽度,但是它是有符号的:

5、

条件表达式:

• 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型。换句话说,你可以通过绕过混合类型的计算来避免大麻烦。
• 如果一个操作数的类型是T,T 表示byte、short 或char,而另一个操作数是一个int 类型的常量表达式,它的值是可以用类型T 表示的,那么条件表达式的类型就是T。
• 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型。

6、

不要将复合赋值操作符作用于byte、short 或char 类型的变量上。在将复合赋值操作符作用于int类型的变量上时,要确保表达式右侧不是long、float或double 类型。

7、

拼接char:

System.out.println("" + 'H' + 'a');
System.out.printf("%c%c", 'H', 'a');

8、

任何两个String类型的常量表达式,如果标明的是相同的字符序列,那么它们就用相同的对象引用来表示。如果用常量表达式来初始化pig 和dog,那么它们确实会指向相同的对象,但是dog 并不是用常量表达式初始化的。

9、

Java 对在字符串字面常量中的Unicode 转义字符没有提供任何特殊处理。编译器在将程序解析成各种符号之前,先将Unicode转义字符转换成为它们所表示的字符。

许多字符都有相应的转义字符序列,包括单引号(\')、换行(\n)、制表符(\t)和反斜线(\\)。

Unicode 转义字符被设计为用于在程序员需要插入一个不能用源文件字符集表示的字符的情况。它们主要用于将非ASCII 字符置于标识符、字符串字面常量、字符字面常量以及注释中。偶尔地,Unicode 转义字符也被用来在看起来颇为相似的数个字符中明确地标识其中的某一个,从而增加程序的清晰度。

10、

/**
* Generated by the IBM IDL-to-Java compiler, version 1.0
* from F:\TestRoot\apps\a1\units\include\PolicyHome.idl
* Wednesday, June 17, 1998 6:44:40 o’clock AM GMT+00:00
*/
这段注释同不过编译,问题在于注释的第三行,它包含了字符\units。这些字符以反斜杠(\)以及紧跟着的字母u 开头的,而它(\u)表示的是一个Unicode 转义字符的开始。遗憾的是,这些字符后面没有紧跟四个十六进制的数字,因此,这个Unicode 转义字符是病构的,而编译器则被要求拒绝该程序。Unicode 转义字符必须是良构的,即使是出现在注释中也是如此。
// Note: \u000A is Unicode representation of linefeed (LF)

这个程序包含了一个Unicode 转移字符(\u000A),它位于程序唯一的注释行中。就像注释所陈述的,这个转义字符表示换行符,编译器将在丢弃注释之前适时地转换它。遗憾的是,这个换行符是表示注释开始的两个斜杠符之后的第一个行终结符(line terminator),因此它将终结该注释[JLS 3.4]。所以,该转义字符之后的字(is Unicode representation of linefeed (LF))就不是注释的一部分了,而它们在语法上也不是有效的。

11、

String str = new String(bytes, "ISO-8859-1");

每当你要将一个byte 序列转换成一个String 时,你都在使用某一个字符集,不管你是否显式地指定了它。如果你想让你的程序的行为是可预知的,那么就请你在每次使用字符集时都明确地指定。

12、

String.replaceAll 接受了一个正则表达式作为它的第一个参数,在正则表达式中的句点必须在其前面添加一个反斜杠(\)进行转义。5.0 版本提供了新的静态方法java.util.regex.Pattern.quote。它接受一个字符串作为参数,并可以添加必需的转义字符,它将返回一个正则表达式字符串

String.replace(CharSequence, CharSequence),它做的事情和String.replaceAll 相同,但是它将模式和替代物都当作字面含义的字符串处理。

13、

import java.util.Random;
public class Rhymes {
private static Random rnd = new Random();
public static void main(String[] args) {
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);
}
}

Random.nextInt(int)的规范描述道:“返回一个伪随机的、均等地分布在从0(包括)到指定的数值(不包括)之间的一个int 数值”。

在不同的情况(case)中没有任何break 语句。不论switch 表达式为何值,该程序都将执行其相对应的case 以及所有后续的case。

StringBuffer 有一个无参数的构造器,一个接受一个String 作为字符串缓冲区初始内容的构造器,以及一个接受一个int 作为缓冲区初始容量的构造器。在本例中,编译器会选择接受int 的构造器,通过拓宽原始类型转换把字符数值'M'转换为一个int 数值77[JLS 5.1.2]。换句话说,new StringBuffer('M')返回的是一个具有初始容量77 的空的字符串缓冲区。该程序余下的部分将字符a、i 和n 添加到了这个空字符串缓冲区中,并打印出该字符串缓冲区那总是ain 的内容。

修正:

import java.util.Random;
public class Rhymes2 {
	private static Random rnd = new Random();
	public static void main(String[] args) {
		System.out.println("PGM".charAt(rnd.nextInt(3)) + "ain");
	}
}
14、

表达式((byte)0x90 == 0x90),尽管外表看起来是成立的,但是它却等于false。byte 是有符号类型。常量0x90 是一个正的最高位被置位的8 位int 数值。合法的byte数值是从-128 到+127,但是int 常量0x90 等于+144。为了比较byte 数值(byte)0x90 和int 数值0x90,Java 通过拓宽原始类型转换将byte 提升为一个int。你可以将int 转型为byte,之后你就可以拿一个byte 与另一个byte 进行比较了:
if (b == (byte)0x90)
System.out.println("Joy!");
或者,你可以用一个屏蔽码来消除符号扩展的影响,从而将byte 转型为int,之后你就可以拿一个int 与另一个int 进行比较了:
if ((b & 0xff) == 0x90)
System.out.print("Joy!");

15、

表达式j++的值等于j 在执行增量操作之前的初始值。
如果你需要的循环会迭代到int 数值的边界附近时,你最好是使用一个long 变量作为循环索引。

16、

while (-1 << i != 0)

移位操作符之使用其右操作数的低5 位作为移位长度。或者是低6 位,如果其左操作数是一个long 类数值。移位长度总是介于0 到31 之间,如果左操作数是long 类型的,则介于0 到63 之间。

for (int val = -1; val != 0; val <<= 1)
可以用任何被计算为无穷大的浮点算术表达式来初始化i,例如:double i = 1.0 / 0.0;不过,你最好是能够利用标准类库为你提供的常量:double i = Double.POSITIVE_INFINITY;
事实上,你不必将i 初始化为无穷大以确保循环永远执行。任何足够大的浮点数都可以实现这一目的,例如:double i = 1.0e40;这样做之所以可以起作用,是因为一个浮点数值越大,它和其后继数值之间的间隔就越大。浮点数的这种分布是用固定数量的有效位来表示它们的必然结果。对一个足够大的浮点数加1 不会改变它的值,因为1 是不足以“填补它与其后继者之间的空隙”。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值