Java作为一门名副其实的工业级语言,语法友好,学习简单,大规模的应用给代码质量的管控带来了困难,特别是团队开发中,开发过程中的规范会直接影响最终项目的稳定性。

善医者“未有形而除之”,提高工程健壮性最好的方式是在代码出现问题之前就排除掉,不给Bug出现的机会。一份好的开发规范就可以起到这样的作用,大大减少产品上线后的问题。

《阿里巴巴Java开发手册》是阿里巴巴的内部编码规范,阿里官方的Java代码规范标准, 手册以Java应用开发为维度,分为编程规约、异常日志规约、MYSQL规约、工程规约、安全规约五个章节,给出了强制、推荐、参考三个级别,每条规范都有推荐的约束力度,从命名到项目拆分,不仅规范了一些开发细节,也提出了很多工程开发的哲学,值得好好阅读。

点击下载《阿里巴巴Java开发手册》(v1.1.0版)

下面记录一些对我比较有启发的条款,提纲挈领,快速学习,方便还没有阅读的同学快速了解。

一、编程规约

1.如果使用到了设计模式,建议在类名中体现出具体模式

将设计模式体现在名字中,有利于阅读者快速理解架构设计思想。

2.相同参数类型,相同业务含义,才可以使用 Java 的可变参数,避免使用 Object

可变参数必须放置在参数列表的最后,尽量不用可变参数编程。

3.对外暴露的接口签名,原则上不允许修改方法签名,避免对接口调用方产生影响

接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么。

4.关于基本数据类型与包装数据类型的使用标准如下

1) 所有的POJO类属性必须使用包装数据类型

2) RPC方法的返回值和参数必须使用包装数据类型

3) 所有的局部变量【推荐】使用基本数据类型

POJO 类属性没有初值是醒使用者在需要使用时,必须自己显式地进行赋值,任何 NPE 问题,或者入库检查,都由使用者来保证。数据库的查询结果可能是null,因为自动拆箱,用基本数据类型接收有NPE风险。

5.注意 serialVersionUID 不一致会抛出序列化运行时异常

序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。

6.POJO 类必须写 toString 方法

使用 IDE 的中工具:source> generate toString 时,如果继承了另一个 POJO 类,注意在前面加一下 super.toString。 在方法执行抛出异常时,可以直接调用 POJO 的 toString()方法打印其属性值,便于排查问题。

7.final 可提高程序响应效率,声明成 final 的情况:

1) 不需要重新赋值的变量,包括类属性、局部变量

2) 对象参数前加final,表示不允许修改引用的指向

3) 类方法确定不允许被重写

8.慎用 Object 的 clone 方法来拷贝对象

对象的 clone 方法默认是浅拷贝,若想实现深拷贝需要重写 clone 方法实现属性对象 的拷贝。

9.类成员与方法访问控制从严

1) 如果不允许外部直接通过new来创建对象,那么构造方法必须是private

2) 工具类不允许有public或default构造方法

3) 类非static成员变量并且与子类共享,必须是protected 4) 类非static成员变量并且仅在本类使用,必须是private

5) 类static成员变量如果仅在本类使用,必须是private

6) 若是static成员变量,必须考虑是否为final

7) 类成员方法只供类内部调用,必须是private

8) 类成员方法只对继承类公开,那么限制为protected

任何类、方法、参数、变量,严控访问范围。过宽泛的访问范围,不利于模块解耦。思考:如果是一个 private 的方法,想删除就删除,可是一个 public 的 Service 方法,或者一个 public 的成员变量,删除一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视线内,变量作用域太大,如果无限制的到处跑,那么你会担心的。

10.ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException 异常

subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList ,而是 ArrayList 的一个视图,对于SubList子列表的所有操作最终会反映到原列表上。

11.使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法

使用add/remove/clear 方法会抛出 UnsupportedOperationException 异常。asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

12.不要在 foreach 循环里进行元素的 remove/add 操作

remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

13.获取单例对象需要保证线程安全,其中的方法也要保证线程安全

资源驱动类、工具类、单例工厂类都需要注意。

14.线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式

这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 Executors 返回的线程池对象的弊端如下: 1)FixedThreadPool 和 SingleThreadPool:

允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

2)CachedThreadPool 和 ScheduledThreadPool:

允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

15.SimpleDateFormat 是线程不安全的类,一般不要定义为static变量

如果定义为static,必须加锁,或者使用 DateUtils 工具类。 注意线程安全,使用 DateUtils。亦推荐如下处理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
} };

16.高并发时,同步调用应该去考量锁的性能损耗

能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

17.并发修改同一记录时,避免更新丢失

要么在应用层加锁,要么在缓存加锁,要么在 数据库层使用乐观锁,使用 version 作为更新依据。 如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次。

18.对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁

19.使用 CountDownLatch 进行异步转同步操作,每个线程退出前必须调用countDown

方法,线程执行代码注意 catch 异常,确保 countDown 方法可以执行,避免主线程无法执行 至 await 方法,直到超时才返回结果。注意,子线程抛出异常堆栈,不能在主线程 try-catch 到。

20.避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一 seed 导致的性能下降。

Random 实例包括 java.util.Random 的实例或者 Math.random()实例。

21.volatile 解决多线程内存不可见问题

对于一写多读,是可以解决变量同步问题, 但是如果多写,同样无法解决线程安全问题。如果是 count++操作,使用如下类实现: AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)。

22.ThreadLocal 无法解决共享对象的更新问题,建议使用 static 修饰

这个变量是针对一个线程内所有操作共有的,所以设置为静态变量,所有此类实例共享 此静态变量 ,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象(只要是这个线程内定义的)都可以操控这个变量。

二、异常日志

1.对大段代码进行 try-catch,这是不负责任的表现

catch 时请分清稳定代码和非稳 定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分 异常类型,再做对应的异常处理。

2.捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之

如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。

3.在代码中使用“抛异常”还是“返回错误码”

对于公司外的 http/api 开放接口必须 使用“错误码”;而应用内部推荐异常抛出;跨应用间 RPC 调用优先考虑使用 Result 方式,封 装 isSuccess、“错误码”、“错误简短信息”。

4.避免出现重复的代码(Don’t Repeat Yourself),即DRY原则

随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。

5.对trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方

6.异常信息应该包括两类信息:案发现场信息和异常堆栈信息

如果不处理,那么往上抛。

三、MySQL 规约

1.表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint ( 1表示是,0表示否),此规则同样适用于odps建表。 任何字段如果为非负数,必须是unsigned。

2.小数类型为 decimal,禁止使用 float 和 double

float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

3.表必备三字段:id, gmtcreate, gmtmodified

其中id必为主键,类型为unsigned bigint、单表时自增、步长为1。gmtcreate, gmtmodified 的类型均为 date_time 类型。

4.单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表

如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。避免过度设计。

5.业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引

6.在 varchar 字段上建立索引时,必须指定索引长度

没必要对全字段建立索引,根据实际文本区分度决定索引长度。 说索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分 度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度 来确定。

7.利用覆盖索引来进行查询操作,来避免回表操作

能够建立索引的种类:主键索引、唯一索引、普通索引,而覆盖索引是一种查询的一种 效果,用explain的结果,extra列会出现:using index。如果索引包含所有满足查询需要的数据的索引成为覆盖索引(Covering Index),也就是平时所说的不需要回表操作

8.利用延迟关联或者子查询优化超多分页场景

MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。

9.SQL 性能优化的目标

至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。

1)consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。 2)ref 指的是使用普通的索引(normal index)。 3)range 对索引进行范围检索。

10.不要使用 count(列名)或 count(常量)来替代 count(*)

count()就是 SQL92 定义 的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。 count()会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。

11.使用 ISNULL()来判断是否为 NULL 值

注意,NULL与任何值的直接比较都为 NULL

12.不得使用外键与级联,一切外键概念必须在应用层解决

外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。

13.iBATIS 自带的 queryForList(String statementName,int start,int size)不推荐使用

其实现方式是在数据库取到 statementName 对应的 SQL 语句的所有记录,再通过 subList 取 start,size 的子集合,线上因为这个原因曾经出现过 OOM。

14.不要写一个大而全的数据更新接口

传入为 POJO 类,不管是不是自己的目标更新字段, 都进行 update table set c1=value1,c2=value2,c3=value3; 这是不对的。

执行 SQL 时,尽量不要更新无改动的字段,一是易出错;二是效率低;三是 binlog 增加存储。

四、工程规约

1.高并发服务器建议调小 TCP 协议的 time_wait 超时时间

操作系统默认 240 秒后,才会关闭处于 timewait 状态的连接,在高并发访问下,服 务器端会因为处于 timewait 的连接数太多,可能无法建立新的连接,所以需要在服务器上 调小此等待值。 正例:在 linux 服务器上请通过变更/etc/sysctl.conf 文件去修改该缺省值(秒): net.ipv4.tcpfintimeout = 30

2.调大服务器所支持的最大文件句柄数(File Descriptor,简写为fd)

主流操作系统的设计是将 TCP/UDP 连接采用与文件一样的方式去管理,即一个连接对应于一个 fd。主流的 linux 服务器默认所支持最大 fd 数量为 1024,当并发连接数很大时很 容易因为 fd 不足而出现“open too many files”错误,导致新的连接无法建立。 建议将 linux 服务器所支持的最大句柄数调高数倍(与服务器的内存数量相关)。

五、安全规约

1. 隶属于用户个人的页面或者功能必须进行权限控制校验

防止没有做水平权限校验就可随意访问、操作别人的数据,比如查看、修改别人的订单。

2. 用户敏感数据禁止直接展示,必须对展示数据脱敏

查看个人手机号码会显示成:158****9119,隐藏中间 4 位,防止隐私泄露。

3. 用户输入的 SQL 参数严格使用参数绑定或者 METADATA 字段值限定,防止 SQL 注入, 禁止字符串拼接 SQL 访问数据库

4. 用户请求传入的任何参数必须做有效性验证

忽略参数校验可能导致: page size过大导致内存溢出 恶意order by导致数据库慢查询 任意重定向 SQL注入 反序列化注入 正则输入源串拒绝服务ReDoS——Java 代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没有问题, 但是如果攻击人员使用的是特殊构造的字符串来验证,有可能导致死循环的效果。

5. 禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据

6. 表单、AJAX 交必须执行 CSRF 安全过滤

CSRF(Cross-site request forgery)跨站请求伪造是一类常见编程漏洞。对于存在 CSRF 漏洞的应用/网站,攻击者可以事先构造好 URL,只要受害者用户一访问,后台便在用户 不知情情况下对数据库中用户参数进行相应修改。

7. 在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防重放限制, 如数量限制、疲劳度控制、验证码校验,避免被滥刷、资损

如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其 它用户,并造成短信平台资源浪费。

8. 发贴、评论、发送即时消息等用户生成内容的场景必须实现防刷、文本内容违禁词过滤等风控策略

阿里巴巴Java开发手册快速学习的更多相关文章

  1. 阿里巴巴Java开发手册正确学习姿势是怎样的?刷新代码规范认知

    很多人都知道,阿里巴巴在2017发布了<阿里巴巴Java开发手册>,前后推出了很多个版本,并在后续推出了与之配套的IDEA插件和书籍. 相信很多Java开发都或多或少看过这份手册,这份手册 ...

  2. 阿里巴巴java开发手册学习记录,php版

    一.编程规约 (一)命名风格 1.目录使用小写+下划线 home,view,model,admin_view 2.类 UpperCamelCase PhpMailer方法 lowerCamelCase ...

  3. 阿里巴巴Java开发手册———个人追加的见解和补充(一)

    先上干货,<阿里巴巴Java开发手册>的下载地址 https://yq.aliyun.com/articles/69327?spm=5176.100239.blogcont69327.15 ...

  4. 读阿里巴巴Java开发手册v1.2.0之编程规约有感【架构篇】

     不为过去蹉跎,改变当下. 为什么开篇就送这么一句话给大家,我相信很多处于1-3年码龄的哥们儿们,在平时的编码历程中编码的个性可能是多彩的,每个人都有每个人特定的风格,但是我们现在这么随意写,以后这么 ...

  5. 《阿里巴巴 Java 开发手册》读书笔记

    偶然看到阿里巴巴居然出书了???趁着满减活动(节约节约....)我赶紧买来准备看看,刚拿到的时候掂量了好多下,总觉得商家给我少发了一本书,结果打开才知道..原来这本书这么小.... 编码规范的重要性 ...

  6. 阿里巴巴Java开发手册评述

    2016年底的时候阿里巴巴公开了其在内部使用的Java编程规范.随后进行了几次版本修订,目前的版本为v1.0.2版.下载地址可以在其官方社区-云栖社区https://yq.aliyun.com/art ...

  7. 读书笔记 之 《阿里巴巴Java开发手册》

    一.前言 这本书主要定义了一些代码的规范以及一些注意事项.我只根据我自己的不足,摘录了一些内容,方便以后查阅. 二.读书笔记 命名 1.代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符 ...

  8. 《阿里巴巴Java开发手册v1.2》解析(编程规约篇)

    之前在乐视天天研究各种底层高大上的东西,因为我就一个人,想怎么弄怎么弄.如今来了新美大,好好研读一下<阿里巴巴Java开发手册v1.2>.还要对这么看似简单的东西解析一番.毕竟现在带团队, ...

  9. 阿里巴巴Java开发手册思维导图

    趁着有时间把阿里巴巴Java开发手册又看了一遍了,很多时候觉得看完之后,发现自己好像一点都不记得了里面的内容了.只能把大概内容画一遍在脑子里形成一张图方便记忆,这样就更能够记得自己的看完的内容了.其中 ...

随机推荐

  1. 《疯狂Java讲义》(七)---- 方法

    一 方法的参数传递机制 Java方法的参数传递方式只有一种:值传递.就是将实际参数值的副本传入方法内,而参数本身不会受到任何影响. eg. 基本类型的值传递 public class Primitiv ...

  2. C++中的输入参考

    1.输入输出 1)operator>> 参考:cplusplus.com Extracts characters from is and stores them in s as a c-s ...

  3. React Router基础使用

    React是个技术栈,单单使用React很难构建复杂的Web应用程序,很多情况下我们需要引入其他相关的技术 React Router是React的路由库,保持相关页面部件与URL间的同步 下面就来简单 ...

  4. CAGradientLayer颜色渐变器

    使用CAGradientLayer可以实现颜色的渐变, 我们先看下头文件 @interface CAGradientLayer : CALayer @property(nullable, copy) ...

  5. 小学生之Hibernate插入数据修改数据使用数据库默认值的实现

    最近在写一个案例,定时任务对数据库进行更新操作,废话不多说,上代码: @Component("taskJob") public class TaskJob extends Hibe ...

  6. LinQ 创建连接、简单增删改查

    LINQ--语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同的方式操 ...

  7. 免越狱tweak应用逆向开发

    对于已越狱的设备,系统默认安装了mobilesubstrate动态库,提供一个系统级的入侵管道,所有的tweak都可以依赖它来进行开发.而对于没有越狱的手机,我们需要向目标app注入libsubstr ...

  8. IPv4地址学习总结

    一. IPv4地址格式 网络互连的一个重要前提条件是要有一个有效的地址结构,并且所有的互连网络用户都应遵守这个地址结构.因为只有这样所有的互连网络用户才能在统一的规定下相互之间通讯.这个地址结构可以有 ...

  9. Oracle VS DB2 数据类型

    =========================Oracle VS DB2==================================== 本文转自:http://www.bitscn.co ...

  10. Jenkins学习——Jenkins是什么

    Jenkins是什么 对于Jenkins是什么,百度百科给的答案是这样的:Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 通过这句话,我们可以得到这样的一 ...