目录
一、创建和销毁对象
1.用静态工厂方法代替构造器:
2.考虑使用构建器:
3.用私有构造器或枚举类型强化Singleton属性:
4.通过私用构造器强化不可实例化的能力:
5.优先考虑依赖注入来引用资源:
6.避免创建不必要的对象:
7.消除过期的对象引用:
8.避免使用终结方法和清除方法:
9.try-with-resource 优于try-finally:声明需要关闭的资源时,优先使用try-with-resource
二、对所有对象都通用的方法
10.覆盖equals时需遵守通用约定:equals()方法要保证自反性、对称性、传递性、一致性、null不等性
11.覆盖equals必须覆盖hashCode:
12.始终要覆盖toString:
13.谨慎的覆盖clone:
14.考虑实现Comparable接口:
三、类和接口
15.使类和成员的可访问性最小化:
16.要在共有类而非公有域中使用访问方法:
17.使可变性最小化:
18.复合优于继承:
19.要么为继承提供文档说明,要么禁止继承
20.接口优先于抽象类:
21.为后代设计接口:
22.接口只能用于定义类型
23.类层次优于标签类:
24.静态成员类优于非静态成员类:
25.限制源文件为单个顶级类:
四、泛型
26.不要使用原生态类型:
27.消除非受检的警告:
28.列表优于数组:
29.优先考虑泛型:
30.优先考虑泛型方法:
31.利用有限制通配符来提升API的灵活性:
32.谨慎并用泛型和可变参数:
33.优先考虑类型安全的异构容器
五、枚举和注解
34.用enum代替int常量:
35.用实例域代替序数:
36.用EnumSet代替位域:
37.用EnumMap代替序数索引:
38.用接口模拟可扩展的枚举:
39.注解优于命名模式:
40.坚持使用Override注解:
41.用标记接口定义类型:
42.Lambda优先于匿名类:
43.方法引用优先于Lambda:
44.坚持使用标准的函数接口:
45.谨慎使用Stream:
46.优先使用Stream中无副作用的函数
47.Stream要优先用Collection作为返回类型:
48.谨慎使用Sream并行:
七、方法
49.检查参数的有有效性:
50.必要时进行保护性拷贝:
51.谨慎设计方法签名:
52.慎用重载:
53.慎用可变参数:
54.返回零长度数组或集合,而不是null
55.谨慎返回optional:
56.为所有导出的API元素编写文档注释
八、通用编程
57.将局部变量的作用域最小化:
58.for-each优先于传统的for循环:
59.了解和使用类库:优先使用最新可靠的代码。
60.如需准确答案,避免使用float和double:
61.基本类型优先装箱类型:
62.如需其他类型更合适,避免使用String类型:
63.了解String的连接性能:
64.通过接口引用对象:
65.接口优先于反射机制:
66.谨慎使用本地方法:
67.谨慎地进行优化:
68.遵守普遍接受地命名惯例:
九、异常
69.只对异常的情况才使用异常:
70.对可恢复的情况使用受检异常,对编程错误使用运行时异常:
71.避免不必要地使用受检异常:
72.优先使用标准的异常:
73.抛出与抽象对应的异常:
74.每个方法抛出的所有异常都要建立文档:
75.在细节消息中包含失败-捕获信息:
76.努力使失败保持原子性:
77.不要忽略异常:
十、并发
78.同步访问共享的可变数据:
79.避免过度同步:
80.executor、task和stream优先于线程:
81.并发工具优先于wait和notify:
82.线程安全性的文档化
83.慎用延迟初始化
84.不要依赖线程调度器
十一、序列化
85.其他方法优于java序列化
86.谨慎地实现Serializable接口
87.考虑使用自定义的序列化方式
88.保护性地编写readObject方法
89.对于实例控制,枚举类型优先于readResolve
90.考虑用序列化代理代替序列化
// Boolean.java
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
// Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8) .calories(100).sodium(35).carbohydrate(27).build();
}
}
// Noninstantiable utility class public class UtilityClass {
public class UtiClass {
private UtiClass() {
throw new AssertionError();
}
}
String s = new String("bikini"); ------> String s = "bikini";
public class RomanNumerals {
private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
static boolean isRomanNumeral(String s) {
return ROMAN.matcher(s).matches();
}
}
实现cloneable接口,并注意是深拷贝还是浅拷贝。
可实现comparable接口,用于后续对该类型的集合排序
迪米特法则:最小知道远原则
如果要对某些属性设置公有属性,提供公有方法,而不是将属性直接设为public
保证实例可变性最小。
优先使用复合,而不是继承:将要复用的类作为一个属性放在扩展类中。
每个继承都要文档说明吗?ide是可以看到继承关系的,是否可以代替文档?我们的系统里基本上没有这种文档
优先使用接口定义方法,而不是抽象类
为避免新的方法导致的错误,建议在类定义时即设计一些必要的接口。
接口只应该用来定义类型,而不是用来导出常量
明确类中层次结构,而不是根据某些标签属性设置其他属性的值。
静态成员类、非静态成员类、匿名类、局部类。
一个源文件只应该声明一个顶级类。
原生态类型(List demo)只是为了保证历史版本兼容性,所有新声明都应该是参数化类型(List
非受检的警告都应该消除,实在消除不了且可保证安全的情况可使用@SuppressWarnings注解
List
如果某些类的参数具有不确定性,优先使用泛型支持此参数。
如果某些类的方法参数具有不确定性,优先使用泛型支持此方法。
约束泛型可变范围
泛型和可变参数不要一起使用,会导致一些不可控的运行时异常。
优先使用枚举类定义某些常量信息
不要使用enum自带的ordinal()方法作为排序
命名模式不可靠,使用注解标明具有某些特性的类/方法/属性
覆盖的方法使用@Override方法,会使方法受检,避免不必要的低级错误。
标明实现了具有某种属性的接口 六、Lambda和表达式
函数接口指只具有一个方法的接口。优先使用Lambda表达式,而不是new XXX{}格式的匿名类。
String::new 等格式的方法引用,优于s->new String()格式的lambada
使用java自带的标准函数接口(Function
Stream虽然语法简洁,但有时代码逻辑不太清晰,注意结合使用
优先返回Collection格式
效率不一定高,且有可能会因为某些并行条件导致假死,以及一些并发问题。
不要相信客户端的输入,校验参数合法性
深拷贝还是浅拷贝,避免对原实例某些属性进行更改。
开闭原则要求对修改关闭,故方法设计之初很重要。
String...args格式的可变参数
还是要额外处理没有值的情况。
优先使用forEach语句,避免一些再次获取单元素item的引用以及有可能造成的低级错误。
每个程序员都应该熟悉java.lang java.util,某种程度上还有java.io中的内容
避免不必要的对象操作,简化操作。
使用更准确的类型。
str1+str2这种格式的操作虽然简单,但性能很差,如有必要可使用StringBuilder
ArrayList list = new ArrayList<>():
// 改为
List list = new ArrayList<>():
反射代码臃肿且性能不高。
尽量避免直接调用native方法
考虑性能与优化的成本。
遵守通用的命名格式,减少沟通理解成本
不要用试图异常处理正常流程的扭转。
明确异常的类型。
能捕获处理就处理,尽量避免重复及不必要的检查
捕获的异常要尽量标准且准确
类似的文档真的有必要吗?
当异常发生时,记录信息,有迹可查
保证程序异常时的原子性,回滚某些状态变化
捕获到异常需要处理,或记录、或处理,不要不作为
可变数据在并发下,要保证能同步访问,synchronized、violate
细化需要同步的代码块
避免创建消毁线程的性能
优先使用concurrent包下的工具类,而不是重量级加锁工具。