前言
做Java开发的,大多数可能都有看过阿里的Java后台开发手册,里面有关于Java后台开发规范的一些内容,基本覆盖了一些通用、普适的规范,但大多数都讲的比较简洁,本文主要会用更多的案例来对一些规范进行解释,以及结合自己的经验做补充!
其他类型的规范
【Java后台开发规范】— 不简单的命名
【Java后台开发规范】— 长函数、长参数
日志输出
关于日志方面的规范其实并不多,也没那么重要,毕竟日志打印这个行为很简单,很单纯,阿里开发手册上有两条关于日志的强制性要求,一个是要求日志文件至少保留15天,一个是有关敏感信息、安全等相关记录的,根据国家法律要求至少保留六个月,日志要保留这么长时间,那自然对于日志的管理就很重要,所以很自然的就有对于日志的命名、分类、日期、拆分等就有了一系列的要求,对于这些我们就不过多说明了。
过多日志
有一些人,可能是为了问题排查方便,50行的代码里有一半都是在打印日志,好像已经养成了一种习惯,在任何方面调用前后都要用日志记录一下方法的入参、出参,我们知道打印日志是存在一定的性能消耗的,可能100ms的方法,有50ms都是因为打印日志造成的。其次增加了日志的存储成本。
无脑打印
add方法调用方和被调用方都打印了相同的内容
public void method() {
log.info("方法method执行开始");
int a = 1, b = 2;
log.info("调用add方法,入参:{},{}", a, b);
int c = add(a, b);
log.info("add方法返回:{}", c);
log.info("方法method执行结束");
}
private int add(int a, int b) {
log.info("方法add执行开始,入参:{},{}", a, b);
int c = a + b;
log.info("add方法返回:{}", c);
return c;
}
map打印的时候已经包含了str1 ,str2的内容
public static void methodA() {
Map<String, String> map = new HashMap<>();
String str1 = "1";
String str2 = "2";
map.put("a", str1);
map.put("b", str2);
log.info("str1:{},str2:{}", str1, str2);
log.info("map:{}", map);
}
可以合一条打印的,没必要打印三次
public static void methodB() {
String str1 = "1";
String str2 = "2";
String str3 = "3";
log.info("str1:{}", str1);
log.info("str2:{}", str2);
log.info("str3:{}", str3);
}
批量打印
在循环体内打印日志
public static void methodC() {
for (int i = 0; i < 100; i++) {
log.info("循环内打印日志: " + i);
}
}
打印大集合数据
public static void methodD() {
int[] arr = new int[1000];
Arrays.fill(arr, 1);
log.info(Arrays.toString(arr));
}
日志中带方法
不要把map或者对象转成String,直接用toString方法输出即可,JSON转String本身就有一定的性能消耗。
public static void methodE() {
Map<String, String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
log.info("没必要把map或者对象通过JSON转成String再打印: {}" , JSON.toJSONString(map));
}
注意不要因为日志输出而引起报错
public static void methodE() {
User user = null;
log.info("调用user中的任何方法都会出现空指针异常: {}", user.toString());
log.info("直接打印user即可: {}", user);
}
讲故事
这个问题典型的表现就是把各种代码逻辑都以日志的形式呈现了出来。
private static void method1(String name) {
User user = new User();
log.info("把user对象的name设置成:{}", name);
user.setName(name);
log.info("当name等于小王时,执行methodA,否则执行methodB");
if (Objects.equals("小王", name)) {
methodA();
} else {
methodB();
}
}
其他基本要求
1、请按照正确的日志级别进行输出,debug、info、warn、error应该要区分清楚。
2、使用占位符的方式输出日志,占位符比使用String拼接要高效。
3、日志输出尽量使用英文,可以有效的减少日志存储大小,也更加符合国际化标准。
以下两条来自阿里规范中的说明
4、大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
5、注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。