阿里-Java开发手册手记(编码规约)

基于Java开发手册 2020泰山版

文章目录

编码规约

命名风格

常量定义

代码格式

采用 4 个空格缩进,禁止使用 tab 字符

idea默认采用4个空格缩进, 请勿勾选 setting > editor > code style > tabs and indents中的Use tab character

IDE 中文件的换行符使用 Unix 格式,不要使用Windows格式

idea默认根据系统采用对应的换行符格式, 可以在setting > editor > code style > general中设置line separator: Unix and macOS(\n)

CR: 回车,MAC老版本的做法,后来的MAC系统统一换成LF了
LF: 换行,Linux下的做法
CRLF: 回车换行,Windows下的做法

OOP规约

所有的覆写方法, 必须加@Override注解

@Override作用

  • 准确判断是否覆盖成功, 避免getObject()与 get0bject()的问题
  • 如果在抽象类中对方法签名进行修改,其实现类会马上编译报错
可变参数
  • 相同参数类型,相同业务含义,才可以使用 Java 的可变参数
  • 避免使用 Object
  • 可变参数必须放置在参数列表的最后
  • 尽量不用可变参数编程
接口过时必须加@Deprecated 注解

@Deprecated 注解

  • 可用于类, 方法, 属性上
  • 通常在给定此注解后,应该在方法注释中同样说明:废弃此方法后的代替方法是哪个、处理原逻辑代替方案是什么 、本身不打算代替,而是直接清除的,则最好给出会清除此方法的具体代码版本号
  • Java 9 中注解增加了两个新元素:@Deprecated(since = "1.2", forRemoval = true)
    • since: 元素指定已注解的API元素已被弃用的版本
    • forRemoval: 元素表示注解的 API 元素在将来的版本中被删除,应该迁移 API
使用常量或确定有值的对象来调用 equals

避免空指针异常, 或使用java.util.Objects#equals

整型包装类对象之间值的比较,使用 equals 方法比较

对于 Integer var = ? 在-128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生,
会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都
会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断

任何货币金额,均以最小货币单位且整型类型来进行存储
  • 运算, 整型运算效率更高
  • 换算展示方便, 比如展示为20元, 而非20.00元
浮点数之间的等值判断,使用BigDecimal判断
  • (1.0f - 0.9f) == (0.9f - 0.8f) //false
禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象

BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常, 如:

new BigDecimal(0.1);	//0.1000000000000000055511151231257827021181583404541015625

推荐使用:

  • new BigDecimal("0.1")
  • BigDecimal.valueOf(0.1)
所有POJO类属性必须为包装数据类型;所有局部变量推荐使用基本数据类型
  • 数据库的查询结果可能是 null,用基本数据类型接收有 NPE 风险
  • 基本数据类型的初值可能对业务逻辑产生影响
POJO 类不要设定任何属性默认值
  • 更新时, 可能更新到未改变的默认值属性
序列化类新增属性时,请不要修改 serialVersionUID 字段
  • 可序列化的类, 必须定义serialVersionUID值
  • serialVersionUID 不一致会抛出序列化运行时异常
POJO 类必须写 toString 方法
  • 在方法执行抛出异常时,可以直接调用 POJO 的 toString()方法打印其属性值,便于排查问题
类内方法定义的顺序依次是:公有方法或保护方法 > 私有方法 > getter / setter方法

公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为承载的信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体最后

getter/setter 方法中,不要增加业务逻辑,增加排查问题的难度
循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展
//反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append
操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费
String str = "start";
for (int i = 0; i < 100; i++) {
str = str + "hello"; }
慎用 Object 的 clone 方法来拷贝对象
  • 对象 clone 方法默认是浅拷贝

日期和时间

日期格式化时,传入 pattern 中表示年份统一使用小写的 y

日期格式化时,yyyy 表示当天所在的年,而大写的 YYYY 代表是 week in which year(JDK7 之后引入的概念),意思是当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,返回的 YYYY就是下一年

在日期格式中分清楚大写的 M 和小写的 m,大写的 H 和小写的 h 分别指代的意义
  • 表示月份是大写的 M
  • 表示分钟则是小写的 m
  • 24 小时制的是大写的 H
  • 12 小时制的则是小写的 h
获取当前毫秒数:System.currentTimeMillis(); 而不是 new Date().getTime()
//使用System.currentTimeMillis(), 效率更高
public Date() {
    this(System.currentTimeMillis());
}

集合处理

list和数组互转
//list转array
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.toArray(new String[0]);
//array转list
//Arrays.asList(strArray)返回值是java.util.Arrays类中一个私有静态内部类java.util.Arrays.ArrayList,它并非java.util.ArrayList类。java.util.Arrays.ArrayList类具有 set(),get(),contains()等方法,但是不具有添加add()或删除remove()方法,所以调用add()方法会报错
String[] strings = {"1", "0"};
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, strings);
不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁
//使用foreach可能抛出ConcurrentModificationException
//应该使用Iterator方式
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String str = iterator.next();
    if ("2".equals(str)) {
        iterator.remove();
    }
}

System.out.println(list);
使用 entrySet或Map.forEach方法遍历Map
//使用Map.forEach方法遍历Map
HashMap<String, String> map = new HashMap<>();
map.put("1", "a");
map.put("2", "b");
map.forEach((k, v) -> System.out.printf("key: %s, value: %s%n", k, v));

并发处理

控制语句

在高并发场景中,避免使用”等于”判断作为中断或退出的条件
  • 例如: 判断剩余奖品数量等于 0 时,终止发放奖品,但因为并发处理错误导致奖品数量瞬间变成了负数,这样的话,活动无法终止
表达异常的分支时,少用 if-else 方式

卫语句(guard clauses)就是把复杂的条件表达式拆分成多个条件表达式,比如一个很复杂的表达式,嵌套了好几层的if-then-else语句,转换为多个if语句,实现它的逻辑,这多条的if语句就是卫语句

public void findBoyfriend (Man man){
	if (man.isUgly()) {
		System.out.println("本姑娘是外貌协会的资深会员");
		return;
	}
	if (man.isPoor()) {
		System.out.println("贫贱夫妻百事哀");
		return;
	}
	if (man.isBadTemper()) {
		System.out.println("银河有多远,你就给我滚多远");
		return; 
	}
	System.out.println("可以先交往一段时间看看");
}
不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性
final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
 ...
}
避免采用取反逻辑运算符
  • 不利于快速阅读

注释规约

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值