四、泛型(完全不懂)
五、枚举和注解
1、用enum代替int常量
- 这个经常用,一般好像都是这么用的了,这里注意有个values()方法挺有意思
public enum Planet {
MERCURY(3.302e+23, 2.439e6), VENUS(4.869e+24, 6.052e6), EARTH(5.975e+24,
6.378e6);
private final double mass;
private final double radius;
private final double surfaceGravity;
private static final double G = 6.67300E-11;
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
surfaceGravity = G * mass / (radius * radius);
}
public double surfaceGravity() {
return surfaceGravity;
}
public double surfaceWeight(double mass) {
return mass * surfaceGravity;
}
}
public static void main(String[] args) {
double earthWeight = 1.0d;
double mass = earthWeight / Planet.EARTH.surfaceGravity();
for (Planet p : Planet.values())
System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
}
2、用实例域代替序数
- 枚举是有顺序的,但是维护起来是噩梦
- 所以现在都是SOLO(1), SUET(2);这样了
3、用EnumSet代替位域
public class Text {
public enum Style {
BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
}
public void applyStyles(Set<Style> styles) {
System.out.println(styles);
}
public static void main(String[] args) {
new Text().applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}
}
4、用EnumMap代替序数索引
- 使用enumMap来索引数据,最好不用序数来索引数组
- 代码没有理解,明天再看
5、用接口模拟可伸缩的枚举
6、注解优先于命名模式
- 以前的类似与JUnit,名字要以Test开头,现在都用注解了
7、坚持使用Override注解
- 如果在想要的每个方法声明中使用Override注解来覆盖超类声明,编译器就可以替你防止大量的错误
8、用标记接口定义类型
- 就比如Serializable,接口没有任何方法
- 例如@Target这样的标记注解,它可以被使用到任何的地方,但是标记接口的优势就是可以更加精确地进行进行锁定
- 总结:如果想定义一个任何新方法都不会与之关联的类型,使用标记接口;如果未来会添加更多的信息,或者使用的不止是类和接口,则使用标记注解。
- 最后一句,如果想要定义类型,一定要使用接口。
六、方法
1、检查参数的有效性
- 例如Collections.sort(List)会隐式的判断里面所有的参数可以进行排序,开销非常巨大
- 总而言之,限制要写到文档里、方法体开头,并通过显式的检查来实施这些限制。
2、必要时进行保护性拷贝
3、谨慎设计方法签名
- 谨慎的选择方法的名称
- 不要过于追求提供便利的方法,对于接口来说方法太多维护、编写困难,对于类和接口所支持的每个动作,都提供一个功能齐全的方法。
- 避免过长的参数列表。目标是4个以内
- 分解方法,不过会造成方法过多
- 创建辅助类,这种类多为静态成员类,用来保存参数分组
- 使用Build模式,第二章第二条
- 对于参数类型,要优先使用接口而不是类,eg:参数是Map,就可以传递HashMap,TreeMap……
- 对于boolean参数要优先使用两个元素的枚举类型。
4、慎用重载
- eg:相同参数列表的构造方法,最少要保证行为的一致
5、慎用可变参数
- eg:int… args,是方便的方式,但是过度滥用会产生混乱的结果
6、返回零长度的数组或者集合,而不是null
- 好处就是所有的地方就不用再判断 != null 了,而且返回null并没有任何理由
7、为所有导出的API元素编写文档注释
七、通用程序设计
1、将局部变量的作用域最小化
- eg: for (int i = 0, n = MAX(); i < n; i++),这样i和n是同一个作用域,减少迭代
- 其他方法:使方法小而集中,或者分开2个方法每个方法各自执行一个操作
2、for-each循环优先于传统的for循环
- 编写简单
- 双重循环之类的没有变量妨碍,代码简单易读
- 注意例外:1、遍历删除选定的参数;2、遍历取代元素值;3、平行迭代多个集合
3、了解和使用类库
- 很多方法不用自己实现了,类库都有,例如random方法就有Random.nextInt(int),不用new Random().自己的方法了
4、如果需要精确的答案,请避免使用float和double
- f和d是为了恶口虚假us那和工程计算而设计的,不是完全的精确结果
- 使用BigDecimal,优点是精确,缺点是麻烦和慢
- 使用int(9位)和long(18位)代替,优点是性能好,缺点是有位数限制
5、基本类型优先于装箱基本类型
- spring等参数绑定默认是Integer,可以防止空指针异常
- 如果是经常使用和变化的变量,肯定还是用int
6、如果其他类型更合适,则尽量避免使用字符串
7、当心字符串连接的性能
8、通过接口引用对象
9、接口优先于反射机制
- 反射缺点
- 反射使用
- 解决:实例化的时候使用反射,访问对象的时候使用已知的接口或者超类
10、谨慎的使用本地方法
11、谨慎的进行优化
12、遵守普遍接收的命名惯例
八、并发
1、多个线程访问可变数据,必须要同步
- synchronized
- 只需要交互通信,不需要互斥则可以使用volatile修饰符,但是需要一些技巧
2、避免过度使用同步
- 防止死锁和数据破坏,同步方法不要调用外来方法
- 减少同步区域内部的工作量
3、executor和task优先于线程
- 看阿里云的代码,已经在使用ExecutorService这样设置县城了
4、并发工具优先于wait和notify
5、慎用延迟初始化
- 大多数的域应该正常地进行初始化
- 如果为了性能目标等,则实例域使用双重检查模式,静态域使用lazy模式