文档章节

阿里Java规范手册学习笔记

尼克air
 尼克air
发布于 2017/02/15 22:46
字数 2284
阅读 102
收藏 2

阿里在2月13日发布了一个32页的java编码规范,应该也是阿里技术部对踩过的坑做的一个总结吧。其中有很多细节也是我平时没有注意到的,所以特此做个笔记,共享。

代码格式规范那块主要就是针对团队协作,避免因为格式问题导致合并的时候有大量的冲突,比较方便的方法是团队用一个code template,idea中可以直接导入导出。

Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals 。

正例: " test " .equals(object);
反例: object.equals( " test " );
说明:推荐使用 java . util . Objects # equals (JDK 7 引入的工具类 )

所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。

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

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

POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何
NPE 问题,或者入库检查,都由使用者来保证。
正例:数据库的查询结果可能是 null ,因为自动拆箱,用基本数据类型接收有 NPE 风险。
反例:比如显示成交总额涨跌情况,即正负 x %, x 为基本数据类型,调用的 RPC 服务,调用
不成功时,返回的是默认值,页面显示:0%,这是不合理的,应该显示成中划线-。所以包装
数据类型的 null 值,能够表示额外的信息,如:远程调用失败,异常退出。

定义 DO / DTO / VO 等 POJO 类时,不要设定任何属性默认值。

反例: POJO 类的 gmtCreate 默认值为 new Date(); 但是这个属性在数据提取时并没有置入具
体值,在更新其它字段时又附带更新了此字段,导致创建时间被修改成当前时间。

循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。

反例:
String str = "start";
for (int I = 0; I < 100; i++) {
str = str + "hello";
}
说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行
append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。

list和array的互换

使用集合转数组的方法,必须使用集合的 toArray(T[] array) ,传入的是类型完全
一样的数组,大小就是 list . size() 。
反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[] 类,若强转其它
类型数组将出现 ClassCastException 错误。
正例:
List<String> list = new ArrayList<String>(2);
list.add("guan");
list.add("bao");
String[] array = new String[list.size()];
array = list.toArray(array);
说明:使用 toArray 带参方法,入参分配的数组空间不够大时, toArray 方法内部将重新分配
内存空间,并返回新数组地址 ; 如果数组元素大于实际所需,下标为 [ list . size() ] 的数组
元素将被置为 null ,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素
个数一致。
使用工具类 Arrays . asList() 把数组转换成集合时,不能使用其修改集合相关的方
法,它的 add / remove / clear 方法会抛出 UnsupportedOperationException 异常。
说明: asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。 Arrays . asList
体现的是适配器模式,只是转换接口,后台的数据仍是数组。
String[] str = new String[] { "a", "b" };
List list = Arrays.asList(str);
第一种情况: list.add("c"); 运行时异常。
第二种情况: str[0]=
"gujin";
那么 list.get(0) 也会随之修改。
ArrayList 的 subList 结果不可强转成 ArrayList ,否则会抛出 ClassCastException
异常: java . util . RandomAccessSubList cannot be cast to java . util . ArrayList ;
说明: subList 返回的是 ArrayList 的内部类 SubList ,并不是 ArrayList ,而是
ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。
在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增
加、删除均产生 ConcurrentModificationException 异常。
泛型通配符<? extends T >来接收返回的数据,此写法的泛型集合不能使用 add 方
法,而 <? super T> 不能使用 get 方法,做为接口调用赋值时易出错。
说明:扩展说一下 PECS(Producer Extends Consumer Super) 原则:1)频繁往外读取内容
的,适合用上界 Extends 。2)经常往里插入的,适合用下界 Super 。

不要在 foreach 循环里进行元素的 remove / add 操作。 remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

反例:
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
if ("1".equals(temp)) {
a.remove(temp);
}
}
说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的
结果吗?
正例:
Iterator<String> it = a.iterator();
while (it.hasNext()) {
String temp = it.next();
if (删除元素的条件) {
it.remove();
}
}

使用 entrySet 遍历 Map 类集合 KV ,而不是 keySet 方式进行遍历。

说明: keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出
key 所对应的 value 。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效
率更高。如果是 JDK 8,使用 Map . foreach 方法。
正例: values() 返回的是 V 值集合,是一个 list 集合对象 ;keySet() 返回的是 K 值集合,是
一个 Set 集合对象 ;entrySet() 返回的是 K - V 值组合集合。

高度注意 Map 类集合 K / V 能不能存储 null 值的情况,如下表格:

集合类KeyValueSuper说明
Hashtable不允许为 null不允许为 nullDictionary线程安全
ConcurrentHashMap不允许为 null不允许为 nullAbstractMap分段锁技术
TreeMap不允许为 null允许为 nullAbstractMap线程不安全
HashMap允许为 null允许为 nullAbstractMap线程不安全

反例: 由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,注意存储 null 值时会抛出 NPE 异常。

在 JDK 7 版本及以上, Comparator 要满足如下三个条件,不然 Arrays . sort ,

Collections . sort 会报 IllegalArgumentException 异常。

说明:
1 ) x , y 的比较结果和 y , x 的比较结果相反。
2 ) x > y , y > z ,则 x > z 。
3 ) x = y ,则 x , z 比较结果和 y , z 比较结果相同。
反例:下例中没有处理相等的情况,实际使用中可能会出现异常:
    new Comparator<Student>() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getId() > o2.getId() ? 1 : -1;
        }
    }

并发处理

  • 获取单例对象需要保证线程安全,其中的方法也要保证线程安全(资源驱动类、工具类、单例工厂类)
  • 创建线程或线程池时请指定有意义的线程名称,方便出错时回溯
  • 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资
源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者
“过度切换”的问题。
  • 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明: Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool :
允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。
2) CachedThreadPool 和 ScheduledThreadPool :
允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。
  • 能用无锁数据结构,就不要用锁 ; 能锁区块,就不要锁整个方法体 ; 能用对象锁,就不要用类锁。
  • 对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造 成死锁。
说明:线程一需要对表 A 、 B 、 C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序
也必须是 A 、 B 、 C ,否则可能出现死锁。
  • 并发修改同一记录时,避免更新丢失,需要加锁。
说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次
数不得小于 3 次。

推荐做法,目的可能是性能,内存问题

  • ArrayList 尽量使用 ArrayList(int initialCapacity) 初始化。

© 著作权归作者所有

共有 人打赏支持
尼克air
粉丝 4
博文 20
码字总数 13259
作品 0
杭州
程序员
私信 提问
《阿里巴巴Java开发手册》2018年完整资料下载!

无规矩不成方圆,无规范不能协作。 《阿里巴巴Java开发手册》(以下简称《手册》)是阿里内部Java工程师所遵循的开发规范,涵盖编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程规...

阿里云云栖社区
10/24
0
0
《阿里巴巴Java开发手册》史上最全资料下载!

无规矩不成方圆,无规范不能协作。 《阿里巴巴Java开发手册》(以下简称《手册》)是阿里内部Java工程师所遵循的开发规范,涵盖编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程规...

云效鼓励师
10/22
0
0
阿里java开发规范学习(附P3C IDEA插件 帮助规范的养成)

浅析 阿里巴巴 Java 开发规约 (未完成) contents 为什么要学 编程规约 P3C IDEA 插件 why-use 我们知道,一般稍微大一点的公司,都会在系统架构设计完成之后,编码工作开始之前,给出一份属于自家...

seltonzyf
05/12
0
0
我有礼品你有故事吗 —— Java 开发规约勾起了你什么样的回忆?

那哥们写的类名首字母居然没大写? 变量名是用下横杠分隔还是驼峰状呢? ON! HashMap 的并发操作导致死循环了! 维护别人写的恶心代码shi简直有想重构的冲动…… 你在 Java 开发时是否遇到过...

两味真火
2017/02/28
3.6K
25
珍藏收集,献出这份年薪50W的阿里Java高级开发内训手册

一、源码阅读 二、分布式架构总纲 分布式应用场景解决方案 三、微服务架构纲要

Java架构
前天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Security 实现 antMatchers 配置路径的动态获取

1. 为什么要实现动态的获取 antMatchers 配置的数据 这两天由于公司项目的需求,对 spring security 的应用过程中需要实现动态的获取 antMatchers ,permitAll , hasAnyRole , hasIpAddre...

大木老师故事的小黄花
5分钟前
0
0
Java 内存模型

一、Java内存模型 硬件处理 电脑硬件,我们知道有用于计算的cpu、辅助运算的内存、以及硬盘还有进行数据传输的数据总线。在程序执行中很多都是内存计算,cpu为了更快的进行计算会有高速缓存,...

微笑向暖wx
5分钟前
0
0
Maven shade的使用

有时你的工程里会和你的Spark环境出现包冲突,这时候可以用Maven shade将你的包名重命名,在maven里加上: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade......

守望者之父
6分钟前
0
0
SpringBoot中导入Excel的总结

1 先导入配置文件 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></dependency><dependency><groupId>org.apache.poi</groupI......

小小小施爷
7分钟前
0
0
python是如何进行内存管理的

Python引入了一个机制:引用计数。 python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要...

糖宝lsh
9分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部