命名风格
1、类名使用UpperCamelCase风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID等。
如:UserDO
2、杜绝完全不规范的缩写,避免望文不知义。
如:AbstractClass“缩写”命名成AbsClass;condition“缩写”命名成 condi,此类随意缩写严重降低了代码的可阅读性。
常量定义
1、不允许任何魔法值(即未经预先定义的常量)直接出现在代码中
如:
String key = "Id#taobao_" + tradeId;
cache.put(key, value);
// 缓存get时,由于在代码复制时,漏掉下划线,导致缓存击穿而出现问题
此处正确的做法应该是维护一个常量表或者在类起始位置定义常量
public static final String PREFIX_TRADEID = "Id#taobao_";
String key=PREFIX_TRADEID+tradeId;
cache.put(key, value);
代码格式
1、代码格式如下
public static void main(String[] args) {
// 缩进4个空格
String say = "hello";
// 运算符的左右必须有一个空格
int flag = 0;
// 关键词if与括号之间必须有一个空格,括号内的f与左括号,0与右括号不需要空格
if (flag == 0) {
System.out.println(say);
}
// 左大括号前加空格且不换行;左大括号后换行
if (flag == 1) {
System.out.println("world");
// 右大括号前换行,右大括号后有else,不用换行
} else {
System.out.println("ok");
// 在右大括号后直接结束,则必须换行
}
}
2、在进行类型强制转换时,右括号与强制转换值之间不需要任何空格隔开。
如:
long first = 1000000000000L;
int second = (int)first + 2;
OOP规约
1、避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。
2、所有的覆写方法,必须加@Override注解。
3、所有整型包装类对象之间值的比较,全部使用equals方法比较。
4、为了防止精度损失,禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象。
说明:BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。如:BigDecimal g = new BigDecimal(0.1f); 实际的存储值为:0.10000000149 正例:优先推荐入参为String的构造方法,或使用BigDecimal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double的实际能表达的精度对尾数进行了截断。
BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1);
5、构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。
集合处理
1、使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。
说明:keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。values()返回的是V值集合,是一个list集合对象;keySet()返回的是K值集合,是一个Set集合对象;entrySet()返回的是K-V值组合集合。
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
map.put("k3", "v3");
// keySet方式,需要遍历两次
System.out.println("=============keySet==================");
Set<String> keySet = map.keySet();
Iterator<String> it1 = keySet.iterator();
while (it1.hasNext()) {
String key1 = it1.next();
String value1 = map.get(key1);
System.out.println("key: " + key1 + " value: " + value1);
}
// entrySet方式,只需遍历一次
System.out.println("=============entrySet==================");
Set<Map.Entry<String, String>> entrySet = map.entrySet();
Iterator<Map.Entry<String, String>> it2 = entrySet.iterator();
while (it2.hasNext()) {
Map.Entry<String, String> entry = it2.next();
String key2 = entry.getKey();
String value2 = entry.getValue();
System.out.println("key: " + key2 + " value: " + value2);
}
// Map.forEach方式
System.out.println("=============Map.forEach==================");
map.forEach((k, v) -> System.out.println("key: " + k + " value: " + v));
}
控制语句
1、当switch括号内的变量类型为String并且此变量为外部参数时,必须先进行null判断。
public class SwitchString {
public static void main(String[] args) {
method(null);
}
public static void method(String param) {
switch (param) {
// 肯定不是进入这里
case "sth":
System.out.println("it's sth");
break;
// 也不是进入这里
case "null":
System.out.println("it's null");
break;
// 也不是进入这里
default:
System.out.println("default");
}
}
}
2、在高并发场景中,避免使用”等于”判断作为中断或退出的条件。
说明:判断剩余奖品数量等于0时,终止发放奖品,但因为并发处理错误导致奖品数量瞬间变成了负数,这样的话,活动无法终止。
日志规约
1、在日志输出时,字符串变量之间的拼接使用占位符的方式。
说明:因为String字符串的拼接会使用StringBuilder的append()方式,有一定的性能损耗。使用占位符仅是替换动作,可以有效提升性能。
logger.debug("Processing trade with id: {} and symbol: {}", id, symbol);