11.关于基本数据类型与包装数据类型的使用标准如下:
1)【强制】所有的POJO类属性必须使用包装数据类型。
2)【强制】RPC方法的返回值和参数必须使用包装数据类型。
3)【推荐】所有的局部变量使用基本数据类型。
说明:POJO类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何NPE问题,或者入库检查,都由使用者来保证。正例:数据库的查询结果可能是null,因为自动拆箱,用基本数据类型接收有NPE风险。反例:比如显示成交总额涨跌情况,即正负x%,x为基本数据类型,调用的RPC服务,调用不成功时,返回的是默认值,页面显示为0%,这是不合理的,应该显示成中划线。所以包装数据类型的null值,能够表示额外的信息,如:远程调用失败,异常退出。
13.【强制】序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值。
说明:注意serialVersionUID不一致会抛出序列化运行时异常
14.【强制】构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。
17.【推荐】使用索引访问用String的split方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛IndexOutOfBoundsException的风险。
说明:String str = "a,b,c,,";
String[] ary = str.split(","); // 预期大于3,结果是3
System.out.println(ary.length);
21.【推荐】循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展。
说明:下例中,反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象,造成内存资源浪费。
反例:
String str = "start";
for(int i=0; i<100; i++){
str = str + "hello";
}
23.【推荐】慎用Object的clone方法来拷贝对象。
说明:对象clone方法默认是浅拷贝,若想实现深拷贝需覆写clone方法实现域对象的深度遍历式拷贝。
24.【推荐】类成员与方法访问控制从严:
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成员方法或成员变量,删除一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视线内,变量作用域太大,无限制的到处跑,那么你会担心的。
集合处理
1.【强制】关于hashCode和equals的处理,遵循如下规则:
1)只要覆写equals,就必须覆写hashCode。
2)因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须覆写这两个方法。
3)如果自定义对象作为Map的键,那么必须覆写hashCode和equals。
说明:String已覆写hashCode和equals方法,所以我们可以愉快地使用String对象作为key来使用。
2.【强制】ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常,即java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。
说明:subList 返回的是ArrayList的内部类SubList,并不是ArrayList而是ArrayList 的一个视图,对于SubList子列表的所有操作最终会反映到原列表上。
3.【强制】使用Map的方法keySet()/values()/entrySet()返回集合对象时,不可以对其进行添加元素操作,否则会抛出UnsupportedOperationException异常。
5.【强制】在subList场景中,高度注意对原集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生ConcurrentModificationException异常
6.【强制】使用集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一致、长度为0的空数组。
反例:直接使用toArray无参方法存在问题,此方法返回值只能是Object[]类,若强转其它类型数组将出现ClassCastException错误。
正例:
List<String> list = new ArrayList<>(2);
list.add("guan");list.add("bao");
String[] array = list.toArray(new String[0]);
说明:使用toArray带参方法,数组空间大小的length:
1)等于0,动态创建与size相同的数组,性能最好。
2)大于0但小于size,重新创建大小等于size的数组,增加GC负担。
3)等于size,在高并发情况下,数组创建完成之后,size正在变大的情况下,负面影响与上相同。
4)大于size,空间浪费,且在size处插入null值,存在NPE隐患。
7.【强制】在使用Collection接口任何实现类的addAll()方法时,都要对输入的集合参数进行NPE判断。
8.【强制】使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。
说明:asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法。
Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。
String[] str = new String[] { "yang", "hao" };Listlist = Arrays.asList(str);
第一种情况:list.add("yangguanbao");运行时异常。
第二种情况:str[0]= "changed"; 也会随之修改,反之亦然。
9.【强制】泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用add方法,而<? superT>不能使用get方法,作为接口调用赋值时易出错。
说明:扩展说一下PECS(Producer Extends Consumer Super)原则:第一、频繁往外读取内容的,适合用<? extends T>。第二、经常往里插入的,适合用<? superT>
11.【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。
正例:
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item=iterator.next(); if (删除元素的条件) {
iterator.remove();
}
}
12.【强制】在JDK7版本及以上,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比较结果相同
15.【推荐】使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历。说明:keySet其实是遍历了2次,一次是转为Iterator对象,另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。
正例:
values()返回的是V值集合,是一个list集合对象;
keySet()返回的是K值集合,是一个Set集合对象;
entrySet()返回的是K-V值组合集合。
建议
时间戳类型: Instant时间戳类
HashMap、Hashtable、ConcurrentHashMap的原理与区别
线程池不允许使用Executors,而是通过ThreadPoolExecutor的方式