-
Notifications
You must be signed in to change notification settings - Fork 0
java guides
以阿里巴巴开发手册1.4.0版本为蓝本,
以阿里的开发手册1.4版(以下简称手册)中的编程规约和异常日志部分为蓝本及基础,并结合其他较为知名的guidelines及组织自身特点,形成一下文本
如果遵循阿里开发手册中的意见(page 1-22),这里不再特别列出,以下,仅记录对手册的修改和补充部分
原文:
【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。 反例:name / name / $name / name / name$ / name
说明:
- 按说这个规则应该是没有争议的,拎出来是内部讨论时候有提到下划线是可能会被用到的,所以这里需要进行补充说明
- 美元符号实际上已经认为是内部类等系统内部使用了
- 下划线有很大一部分是源于其他语言,比如python,在java中不适用
- 有听过老程序员提到,有代码生成工具通过下划线来生成类似setter或getter这类的代码,java世界有如果有,现在也已经废弃了
- 这条guideline没有对中间的下划线做出规定,从后面的对于驼峰命名法的几条约束来看,它不鼓励蛇形命名法及其和驼峰的混用,但在Google Java Style Guide 中提到JUnit的test method有一种例外,混合驼峰和蛇形命名法是被接受的命名模式
原文:
【强制】类名使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等。
正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
修改为:
- 【强制】类名使用UpperCamelCase风格,遇到缩写和不常见结构体时,遵循google java style guides中规则
说明:
- 阿里这条比较拧巴,为什么TCP UDP就要按驼峰而这些例外不要?豁免权的来源完全搞不清楚,估计是其内部对现状的妥协,这么去落实,实际上是在违反一致性原则;如果真是遗留代码的问题,应当给一个对旧代码的整体例外约束比较好,这一点在Google的 C++ Style Guide中有明确的章节来说明,所以说java还是年轻?
原文:
【推荐】使用索引访问用 String 的 split 方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛IndexOutOfBoundsException 的风险。
说明:
String str = "a,b,c,,"; String[] ary = str.split(","); // 预期大于 3,结果是 3 System.out.println(ary.length);
修改并补充:
- 【推荐】使用索引访问用 String 的 split 方法得到的数组时,要对数组长度做检查,否则会有抛IndexOutOfBoundsException 的风险
- 【推荐】如果允许split结果数组中有空字符串,那么可以使用split(regex,-1)来进行切分来达到设计目的
说明:
- 手册意图比较明确,但是说错了;实际上应该检查的是数组长度,也就是生产代码中防范这种非受控异常,手册说明部分本意是这个问题
- 手册应当还有一个意图,就是它期望能取到最后那个空字符串,这时靠检查是没用,而应当对正则的匹配限定limit,补充部分强调的就是这部分
- 另外不要对split加limit为-1做出限定,否则就会失去一个功能,split(regex)是两个参数split的一个特例,详见JDK的Java doc
原文:
【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起, 便于阅读,此条规则优先于第 16 条规则。
修改:
- 【推荐】重载方法要放置在一起,中间不要插入其他任何内容,此条规则优先于第 16 条规则。
说明:
- 推荐按顺序又没给出应该按什么顺序,参数的字母顺序?参数数量?和关联的16条一看大概明白他的意思了,这两条合在一起应该都是给一个通用准则的狗尾续貂
原文:
【推荐】 类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。
说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类 关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个 黑盒实现;因为承载的信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体最后
修改:
- 【推荐】 类的成员要按照逻辑规则进行组织
说明:
这个问题也是容易引起争议的地方,考虑到手册仅仅是推荐,因此不对它这里缺少原则、涉及内容不全面、令人疑惑的说明做出修改描述,仅做一补充说明
先细说一下手册的问题:
- 只涉及了方法顺序,没涉及成员变量,那就更不用提静态初始化块儿的了
- 可能是阿里得同学都不用包可见级别
- getter/setter的顺序解释很奇特,这里详细说下
- 这个世代需要在service或这DAO这两层类型写accessor这种方法的情况应该已经很少了,通常是基于注解并通过DI框架来完成功能
- 大量需要getter/setter方法的类通常也只有getter/setter(典型的贫血模型+事务脚本这种实现模式)
- 大量需要getter/setter方法的类是值对象,贫血模型,通常现在应当鼓励使用类似Lombok或者AutoValue这类类库来减少撰写和维护时无谓的工作量,当然损失掉的是这部分类型源码和字节码一一对应这个Java特性
唯一能确定的顺序是顺序必须按照某种类内逻辑关系来组织,但是问题就在于这种逻辑关系实际上一般不具有普适性,所以很难具体规定出来,这里摘抄翻译的 google style guide关于这里的建议如下:
3.4.2 类内部定义的顺序
类中成员和初始化函数顺序的选择对于该类设计的理解上有很大的影响。然而是没有唯一正确的守则来确定如何去做;不同的类可能用不同的顺序来组织他们内容的顺序才是合适的 重要的是每个类要使用某种确定的逻辑顺序来进行组织,他的维护者要能解释清楚这种逻辑顺序;例如,新的方法不能习惯性的在类的最下面一放就完事了,因为这样就变成了“明摆着的按时间添加”顺序,而不是逻辑顺序 3.4.2.1 重载:绝不要拆开 当一个类有多个构造函数,或者多个方法使用了相同的方法名,那么他们应该紧挨着撰写,中间不要插入任何代码(就算是私有的成员也不要不要)
这种原则性描述基本上够了,再往上添加很有可能变成立场之争,浪费生命;回过头来再看一下手册的说明,能探出它基本思路是鼓励封装和隔离的,但是理由阐述的并不充分甚至可能是错的和混乱的:
- 调用者和维护者立场不同最关心的不可能,也不应该一样:
- 维护者最关心对外接口要甚于实现细节?
- 对外接口视图难道不应该是interface去集中表达吗?
- 调用者难道不该使用接口吗?
- 等到最后service/DAO的accessor之论已经乱套的一塌糊涂了,这个上面已经罗列过了
如果需要一个更有可操作性的指导,可以考虑在满足更具内在逻辑表达的情况下,可见性高的放前面,如果有public的因为其他public的method关联性更强的private挤到好几屏以后了,那应该考虑内聚性的问题,该拆类了