偶然看到阿里巴巴居然出书了???趁着满减活动(节约节约….)我赶紧买来准备看看,刚拿到的时候掂量了好多下,总觉得商家给我少发了一本书,结果打开才知道..原来这本书这么小….
别人都说我们是搬砖的码农,但我们知道自己是追求个性的艺术家。也许我们不会过多在意自己的外表和穿着,但在我们不羁的外表下,骨子里追求着代码的美、系统的美、设计的美,代码规范其实就是一个对程序美的定义。—— 引自 序
如果有一天在我们的项目中看到了这样的代码:
或者是这样的代码:
这样美不美呢?或许看着是还挺美的,但是如果需要修改,是不是人傻啦?
那这样的代码呢?
作为一个对自己有一定要求的程序猿,是不是第一反应就是:
规范不一,就会像下图中的小鸭和小鸡对话一样,语言不通,一脸囧相。鸡同鸭讲也恰恰形容了人与人之间沟通的痛点,自说自话,无法达成一致意见。再举一个生活中的例子,交通规则靠左行驶还是靠右行驶,两者孰好孰坏并不重要,重要的是必须要在统一的方向上通行,表面上限制了自由,但实际上是保障了公众的人身安全。试想,如果没有规定靠右行驶,那样的路况肯定拥堵不堪,险象环生。同样,过分自由随意、天马行空的代码会严重的伤害系统的健康,影响到可扩展性以及可维护性。
众所周知,互联网公司的优势在于效率,它是企业核心竞争力。体现在产品开发领域,就是够沟通效率和研发效率。对于沟通效率的重要性,可以从程序猿三大 “编码理念之争” 说起:
在美剧《硅谷》中,有这样的一个经典镜头:
Tab 键和空格键的争议确实存在,并且在知乎上讨论得火热:写代码时,缩进使用 tab 还是空格?
if 单语句是否需要换行,也是争论不休的话题。相对来说,写过格式缩进类编程语言的开发者, 更加习惯于不加大括号。《手册》中明确 if/for 单行语句必须加大括号,因为单行语句的写法,容易在添加逻辑时引起视觉上的错误判断。此外,if 不加大括号还会有局部变量作用域的问题。
左大括号是否单独另起一行?因为 Go 语言的强制不换行,在这点上,“编程理念之争” 的硝烟味似乎没有那么浓。如果一定要给一个理由,那么换行的代码可以增加一行,对于按代码行数考核工作量的公司员工,肯定倾向于左大括号前换行。《手册》明确左大括号不换行!
这一章是对传统意义上的代码规范,包括变量命名、代码风格、控制语句、代码注释等基本的变成习惯,以及从高并发场景中提炼出来的集合处理技巧与并发多线程的注意事项。
- 反例:
_name
/$name
/name_
/name$
尽管 $
可以作为标识符使用,然而我们应该尽量避免对其使用。
$
通常在编译器生成的标识符名称中使用,如果我们也使用这个符号,可能会有一些意想不到的错误发生….package test;
public class User$VIP {
public static void main(String[] args) {
User user = new User();
User.VIP vip = user.new VIP();
vip.print();
}
}
class User{
class VIP{
void print(){
System.out.println("成员类");
}
}
}
仔细阅读以下,似乎并没有什么问题,代码也比较简单,但正在我们编译的时候,IDEA提示我们:
定义了重复的代码?归根到底,都是 $
惹的祸!因为 $
被编译器所使用,在源文件(.java 文件)编译成字节码(.class 文件)后,会称为顶层类型与嵌套类型之间的连接符。例如,如果存在一个顶层类 A,在其内声明了一个成员类 B,那么编译之后就会产生两个 class 文件,分别为 A.class
与 A$B.class
。
就本程序来说,会生成 3 个 class 文件(如果可以编译的话),分别是 User$VIP.class
(顶层类)、User.class
与 User$VIP.class
(User 类的成员类,也就是类 VIP)。由于试图存在两个 User$VIP.class
所以才会报错!
变量命名全部大写,单词兼用下划线隔开,力求予以表达完整清楚,不要嫌名字太长。
正例:MAX_STOCK_COUNT / PRIZE_NUMBER_EVERYDAY
反例:MAX_COUNT / PRIZE_NUMBER
抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类名开始,以 Test 结尾。
反例:定义为基本数据类型
Boolen isDeleted;
的属性,它的方法名称也是isDeleted()
,RPC 框架在反向解析的时候,“误以为” 对应的属性名称是deleted
,导致属性获取不到抛出异常。
正例:
public class OrderFactory;
public class LoginProxy;
public class ResourceObserver;
正例:
接口方法签名:void commit();
接口基础变量:String COMPANY = "alibaba";
反例:
接口定义方法:public abstract void commit();
正例: CacheServiceImpl 实现 CacheServcie 接口
- 2):【推荐】 如果是形容能力的接口名称,取对应的形容词为接口名(通常是 -able 的形式)。
正例: AbstractTranslator 实现 Translatable。
Long a = 2l;
写得是数字的 21 还是 Long 型的 2?正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在 ConfigConsts 下。
public static void main(String[] args){
// 注释的双斜线与注释内容之间有且仅有一个空格
// 缩进 4 个空格
String say = "hello";
// 运算符的左右必须有 1 个空格
int flag = 0;
// 关键字 if 与括号之间必须有 1 个空格,括号内的 f与左括号、
// 0 与右括号之间不需要空格
if (flag == 0) {
System.out.println(say);
}
// 左大括号前加空格且不换行;左大括号后换行
if (flag == 1) {
System.out.println("world");
// 右大括号前换行,右大括号后有 else,不用换行
} else {
System.out.println("ok");
// 在右大括号后直接结束,则必须换行
}
}
正例:下例中实参的“one”,后边必须要有一个空格。
method("one", "two", "three");
Intergre var = ?
在 -128~127 范围内的赋值, Integer 对象是在 IntegerCache.cache 中产生的,会复用已有的对象,这个区间内的 Integer 值可以直接使用 == 进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象。这是一个大坑,推荐使用 equals 方法进行判断。// 正例
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (删除元素的条件) {
iterator.remove();
}
}
// 反例
List list = new ArrayList<>();
list.add("1");
list.add("2");
for (String item : list) {
// 如果把 1 改为 2 再试一下看看是否相同
if ("1".equals(item)) {
list.remove(item);
}
}
if (condition) statements;
反例:判断剩余奖品数量等于 0 时,终止发放奖品,但因为并发处理错误导致奖品数量瞬间变成了负数,这样的话,活动无法终止。
// 正例:超过 3 层的 if-else 逻辑判断代码可以使用卫语句、策略模式
// 状态模式等来实现,其中卫语句实例如下:
public void today() {
if (isBusy()) {
System.out.println("change time,");
return;
}
if (isFree()) {
System.out.println("go to travel.");
return;
}
System.out.println("stay at home to learn Java");
return;
}
/**内容*/
格式,不得使用 //xxx
方式“安全生产,责任重于泰山。” 这句话同样适用于软件生产,本章主要说明编程中需要注意的比较基础的安全准则。
正例: getter _ admin , task _ config , level 3_ name
反例: GetterAdmin , taskConfig , level 3 name
正例: tiger _ task / tiger _ reader / mpp _ config
正例:如下表,其中无符号值可以避免误存负数,且扩大了表示范围。
对象 | 年龄区间 | 类型 | 表示范围 |
---|---|---|---|
人 | 150 岁之内 | unsigned tinyint | 无符号值:0 到 255 |
龟 | 数百岁 | unsigned smallint | 无符号值:0 到 65535 |
恐龙化石 | 数千万年 | unsigned int | 无符号值:0 到约 42.9 亿 |
太阳 | 约 50 亿年 | unsigned bigint | 无符号值:0 到约 10 的 19 次方 |
正例: where a =? and b =? order by c; 索引: a _ b _ c
反例:索引中有范围查找,那么索引有序性无法利用,如: WHERE a >10 ORDER BY b; 索引 a _ b 无法排序。
正例:如果 where a =? and b =? , a 列的几乎接近于唯一值,那么只需要单建 idx _ a 索引即可。
整个规约对自己来说都挺有用的,因为正好涉及到这方面,幸好感觉脸不怎么疼。
浏览了一遍,还是学习到了很多东西吧,上面也仅仅只是总结了对我自己比较收益,现阶段我能吸收能实际感受得到的规约,如果想要 PDF 版的可以在这里下载:戳这里
欢迎转载,转载请注明出处!
@我没有三颗心脏
CSDN博客:http://blog.csdn.net/qq939419061
简书:http://www.jianshu.com/u/a40d61a49221