解读《Java开发手册(泰山版)》- 会当凌绝顶,一览众山小

204 阅读6分钟

这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战

阿里的《Java开发手册》被Java开发者所拜读,基本人手一册,在 2020.04.22 发布了泰山版 - 会当凌绝顶,一览众山小,而这次发布新增了很多干货内容,在此,给大家分享一下,是时候更新你的手册了。

从文末【附1:版本历史】,记录来看,本次泰山版更新内容如下:

  • 发布错误码统一解决方案
  • 新增 34 条新规约。比如,日期时间的闰年、闰月问题,三目运算的自动拆箱,SQL查询的表别名限定,Collectors 类的 toMap()方法使用注意等。
  • 修改描述 90 处。比如,阻塞等待锁、建表的小数类型等。
  • 完善若干处示例。比如,ISNULL 的示例等。

在此,尝鲜解读,分享给大家。

(规范性的东西,在实际使用过程中,只是作为一种通用的参考,切勿过分照搬!)

一、错误码

之前版本中没有涉及过关于“错误码”的内容,而在这个版本中新增了一小节来描述了“错误码”部分,并做了详细的说明。

错误码,作为任何一个系统中必不可少的要素,但好多时候错误码的不规范、不统一使用,便会对后期开发、使用造成很大的困扰。本次版本,“错误码”的出现,给广大开发者在定义错误码时提供的参考、建议,可谓福利。

具体规范如下:

  1. 【强制】错误码的制定原则:快速溯源、简单易记、沟通标准化
  2. 【强制】错误码不体现版本号和错误等级信息。
  3. 【强制】全部正常,但不得不填充错误码时返回五个零:00000。
  4. 【强制】错误码为字符串类型。
  5. 【强制】编号不与公司业务架构,更不与组织架构挂钩,一切与平台先到先申请的原则进行,审批生效,编号即被永久固定。
  6. 【强制】错误码使用者避免随意定义新的错误码。
  7. 【强制】错误码不能直接输出给用户作为提示信息使用。
  8. 【参考】错误码分为一级宏观错误码、二级宏观错误码、三级宏观错误码。即:分类定义错误码,便于归类。
  9. ……

个人建议:

  • 错误码格式一定统一、规范化,切勿杂乱无章定义。
  • 分类定义错误码,便于归类。即:按实际来进行多级分类,如前两位代指服务编号,次一位代指错误类别,再次之代指具体错误编号。
  • 错误码切记重复。

二、日期时间规范

新增"日期时间"的编程规范,都是些细节问题,稍加思考、留意,就可避免。规范如下:

  1. 【强制】日期格式化时,传入 pattern 中表示年份统一使用小写的 y。
  2. 【强制】在日期格式中分清楚大写的 M 和小写的 m,大写的 H 和小写的 h 分别指代的意义。
  3. 【强制】获取当前毫秒数:System.currentTimeMillis(); 而不是 new Date().getTime()。
  4. 【强制】不允许在程序任何地方中使用:1)java.sql.Date 2)java.sql.Time 3)java.sql.Timestamp。
  5. 【强制】不要在程序中写死一年为 365 天,避免在公历闰年时出现日期转换错误或程序逻辑错误。

稍有些常识的人都知道,不可能每年都是365天的。

正例:

// 获取今年的天数

int daysOfThisYear = LocalDate.now().lengthOfYear();

// 获取指定某年的天数

LocalDate.of(2011, 1, 1).lengthOfYear();

反例:

// 第一种情况:在闰年 366 天时,出现数组越界异常

int[] dayArray = new int[365];

// 第二种情况:一年有效期的会员制,今年 1 月 26 日注册,硬编码 365 返回的却是 1 月 25 日Calendar calendar = Calendar.getInstance();

calendar.set(2020, 1, 26);

calendar.add(Calendar.DATE, 365);
  1. 【推荐】避免公历闰年 2 月问题。闰年的 2 月份有 29 天,一年后的那一天不可能是 2 月 29日。
  2. 【推荐】使用枚举值来指代月份。如果使用数字,注意 Date,Calendar 等日期相关类的月份month 取值在 0-11 之间。

三、三目运算符

【强制】三目运算符 condition? 表达式 1 : 表达式 2 中,高度注意表达式 1 和 2 在类型对齐时,可能抛出因自动拆箱导致的 NPE(NullPointerException) 异常。

以下两种场景会触发类型对齐的拆箱操作:

1) 表达式 1 或表达式 2 的值只要有一个是原始类型。

2) 表达式 1 或表达式 2 的值的类型不一致,会强制拆箱升级成表示范围更大的那个类型。

反例:


Integer a = 1;

Integer b = 2;

Integer c = null;

Boolean flag = false;

// a*b 的结果是 int 类型,那么 c 会强制拆箱成 int 类型,抛出 NPE 异常

Integer result=(flag? a*b : c);

四、表别名

【强制】对于数据库中表记录的查询和变更,只要涉及多个表,都需要在列名前加表的别名(或表名)进行限定。

说明:对多表进行查询记录、更新记录、删除记录时,如果对操作列没有限定表的别名(或表名),并且操作列在多个表中存在时,就会抛异常。

正例:

select t1.name from table_first as t1 , table_second as t2 where t1.id=t2.id;

反例:在某业务中,由于多表关联查询语句没有加表的别名(或表名)的限制,正常运行两年后,最近在某个表中增加一个同名字段,在预发布环境做数据库变更后,线上查询语句出现出 1052 异常:Column 'name' in field list is ambiguous。

【推荐】SQL 语句中表的别名前加 as,并且以 t1、t2、t3、...的顺序依次命名。说明:

1)别名可以是表的简称,或者是根据表出现的顺序,以 t1、t2、t3 的方式命名。

2)别名前加 as使别名更容易识别。

正例:

select t1.name from table_first as t1, table_second as t2 where t1.id=t2.id;

五、总结

《Java开发手册》,在许多公司常常作为新员工的必读资料,作为公司开发规范的参考,在广大Java开发者的职业生涯中发挥着重要的作用。

以上只是针对其中很少部分内容的解读、复述,在我们日常开发中很有借鉴、参考意义,至少它会避免我们犯很多错误。