- 不要在常量和变量中出现易混淆的字母
- 莫让常量蜕变成变量
常量就是常量,在编译期就必须确定其值,不应该在运行期更改
务必让常量的值在运行期保持不变 - 三元操作符的类型务必一致
三元操作符是if-else的简化写法
int i=80;
System.out.println(String.valueOf(i<100 ? 90 : 100));
System.out.println(String.valueOf(i<100 ? 90 : 100.0));
运行结果:
三元操作符类型转换规则:
- 若两个操作数不可转换,则不做转换,返回值为Object类型
- 若两个操作数是明确类型的表达式(比如变量),则按照正常的二进制数字来转换,int转换为long,long转换为float等
- 如两个操作数中有一个数字S,另外一个是表达式,且其类型标示为T,那么若数字S在T的范围内,则转换为T的类型;否则T转为S类型。返回值类型为范围较大者。
- 避免带有变长参数的方法重载
- 别让null值和空值威胁到变长方法
- 覆写变长方法也循规蹈矩(覆写的方法参数与父类相同,不仅仅是类型、数量,还包括显示形式)
- 警惕自增的陷阱
int count = 0;
for (int i=0;i<10;i++){
count = count++;
}
System.out.println("count="+count);
上面这段代码的输出结果居然是:count=0
count++ 是一个表达式,是有返回值的,它的返回值就是count自加前的值。
Java对自加是这样处理的:
1、把count的值拷贝到一个临时变量区
2、对count变量加1
3、返回临时变量区的值
int count = 0;
for (int i=0;i<10;i++){
count = ++count;
}
System.out.println("count="+count);
int count = 0;
for (int i=0;i<10;i++){
count++;
}
System.out.println("count="+count);
上面两段代码的输出结果都是:count=10
8. 不要让旧语法困扰你
9. 少用静态导入
对于静态导入,一定要遵循两个规则:
- 不使用*通配符,除非是导入静态常量类(只包含常量的类或接口)
- 方法名是具有明确、清晰表象意义的工具类
滥用静态导入会使程序更难阅读,更难维护。静态导入后,代码中就不用再写类名了,静态属性和静态方法的表象意义可以被无限放大,让阅读者难以理解。
10. 不要在本类中覆盖静态导入的变量和方法
11. 养成良好习惯,显示声明UID
类实现Serializable
接口的目的是为了可持久化,比如网络传输或本地存储,为系统的分布和异构部署提供先决支持条件。
serialVersionUID
,也叫流标识符,即类的版本定义,它可以显式声明也可以隐式声明
private static final long serialVersionUID = 1L;
显式声明serialVersionUID可以避免对象不一致。
12. 避免用序列化类在构造函数中为不变量赋值
在序列化类中,不使用构造函数为final变量赋值(反序列化时构造函数不会执行)。
13. 避免为final变量复杂赋值
反序列化时final变量在以下情况下不会被重新赋值:
- 通过构造函数为final变量赋值
- 通过方法返回值为final变量赋值
- final修饰的属性不是基本类型
- 使用序列化类的私有方法巧妙解决部分属性持久化问题
部分属性持久化,可以通过把不需要持久化的属性加上transient关键字。
实现了Serializable接口的类可以实现两个私有方法writeObject和readObject,以影响和控制序列化和反序列化的过程。
(个人认为还是不要乱用这两个方法了) - break万万不能忘
- 易变业务使用脚本语言编写
- 慎用动态编译
- 避免instanceof非预期结果
public class GenericClass<T> {
public boolean isDateInstance(T t){
return t instanceof Date;
}
}
运行结果:
b1 : true
b2 : true
b3 : false
b5 : false
b6 : false
b8 : false
boolean b4 = 'A' instanceof Character;
这个编译不通过,因为'A'是一个char类型,也就是一个基本类型,不是一个对象,
instanceof只能用于对象的判断,不能用于基本类型的判断
boolean b5 = null instanceof Object;
boolean b6 = (String)null instanceof String;
若左操作数为null,直接返回false
boolean b7 = new Date() instanceof String;
编译不通过是因为Date类和String类没有继承和实现关系;
boolean b8 = new GenericClass<String>().isDateInstance("");
Java泛型是为编码服务的,在编译字节码时,T已经是Object类型了,传递的实参是String类型。
- 断言绝对不是鸡肋
Java中的断言使用的是assert关键字,用法如下:
assert <布尔表达式>
assert <布尔表达式> : <错误信息>
布尔表达式为假时,抛出AssertionError,并附带了错误信息。
20. 不要只替换一个类
发布应用系统时禁止使用类文件替换方式,整体WAR包发布才是万全之策。
《编写高质量代码:改善Java程序的151个建议》