Java开发手册-3

编程规约

日期时间

  1. 【强制】日期格式化时,传入pattern中表示年份统一使用小写的y
    说明:日期格式化时,yyyy表示当天所在的年,而大写的YYYY代表是week in whichyear,意思是当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,返回的YYYY就是下一年。
    正例:表示日期和时间的格式如下所示: java new SimpleDateFormat("yyy-MM-dd HH:mm:ss")

    反例:某程序员因使用YYYY/MM/dd进行日期格式化,2017/12/31执行结果为2018/12/31,造成线上故障。

  2. 【强制】在日期格式中分清楚大写的M和小写的m,大写的H和小写的h分别指代的意义。
    说明:日期格式中的这两对字母表意如下:
    (1)表示月份是大写的M
    (2)表示分钟则是小写的m
    (3)24小时制的是大写的H
    (4)12小时制的则是小写的h

  3. 【强制】获取当前毫秒数:System.currentTimeMilli();而不是new Date().getTime()
    说明:获取纳秒级时间,则使用System.nanoTime的方式。在JDK8中,针对统计时间等场景,推荐使用Instant类。

  4. 【强制】不允许在程序任何地方中使用:
    (1)java.sgl.Date
    (2)java.sql.Time
    (3)java.sql.Timestamp
    说明:第1个不记录时间,getHours()抛出异常;第2个不记录日期,getYear()抛出异常;第3个在构造方法super((time/1000)*1000),在Timestamp属性fastTimenanos分别存储秒和纳秒信息。
    反例:java.util.Date.after(Date)
    进行时间比较时,当入参是java.sql.Timestamp时,会触发JDK BUG(JDK9已修复),可能导致比较时的意外结果。

  5. 【强制】禁止在程序中写死一年为365天,避免在公历闰年时出现日期转换错误或程序逻辑错误。
    正例:

    //获取指定某年的天数 LocalDate.of(2011,1,1).lengthOfYear(); ```
    
    <font color =A52A2A>反例:</font>
    
    ```java //第一种情况:在闰年366天时,出现数组越界异常 int[] dayArray = new int[365];
    //第二种情况:一年有效期的会员制,2020年1月26日注册,硬编码365返回的却是2021年1月25日 Calendar
    calendar = Calendar.getInstance(); calendar.set(2020, 1, 26);
    calendar add(Calendar DATE, 365); ```
    
  6. 【推荐】使用枚举值来指代月份。如果使用数字,注意DateCalendar等日期相关类的月份month取值范围从0到11之间。
    说明:参考JDK原生注释,Month value is 0-based.e.g.,0 for January.
    正例:Calendar.JANUARY,Calendar.FEBRUARY,Calendar.MARCH等来指代相应月份来进行传参或比较。

集合处理

  1. 【强制】关于hashCodeequals的处理,遵循如下规则:
    (1)只要覆写equals,就必须覆写hashCode
    (2)因为Set存储的是不重复的对象,依据hashCodeequals进行判断,所以Set存储的对象必须覆写这两种方法。
    (3)如果自定义对象作为 Map 的键,那么必须覆写 hashCodeequals
    说明:String因为覆写了hashCode和equals方法,所以可以愉快地将String对象作为key来使用。

  2. 【强制】判断所有集合内部的元素是否为空,使用isEmpty()方法,而不是size() == 0的方式。
    说明:在某些集合中,前者的时间复杂度为O(1),而且可读性更好。
    正例:

    Map<String, Object>map = new HashMap<>(16); 	
    if (map.isEmpty() { 		
    	System.out.println("no element in this map."); 	
    }
    
  3. 【强制】Collections类返回的对象,如:emptyList()/singletonList()等都是immutable list,不可 对其进行添加或者删除元素的操作。
    反例:
    如果查询无结果,返回 Collections.emptyList()空集合对象,调用方一旦在返回的集合中进行了添加元素的操作,就会触发UnsupportedOperationException异常。

  4. 【强制】使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为0的空数组。 反例:直接使用toAray无参方法存在问题,此方法返回值只能是Object[]类,若强转其它类型数组将出现ClassCastException错误。
    正例:

    list.add("bao"); String[] array = list.toArray(new String[0]); ```
    
    <font color =#CD853F>说明:</font>使用`toArray`带参方法,数组空间大小的`length`:
    (1)等于`0`,动态创建与`size`相同的数组,性能最好。
    (2)大于`0`但小于`size`,重新创建大小等于`size`的数组,增加GC负担。
    (3)等于`size`,在高并发情况下,数组创建完成之后,`size`正在变大的情况下,负面影响与`2`相同。
    (4)大于`size`,空间浪费,且在`size`处插入`null`值,存在`NPE`隐患。
    
  5. 【强制】使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出
    UnsupportedOperationException异常。
    说明:asList的返回对象是一个Arrays内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

    list = Arrays.asList(str); ```
    
    第一种情况:`list.add("yangguanbao");`运行时异常。 第二种情况:`str[0]
    ="change"`;`list`中的元素也会随之修改,反之亦然。
    
  6. 【强制】泛型通配符<?extends T>来接收返回的数据,此写法的泛型集合不能使用add方法,而<?super T>不能使用 get方法,两者在接口调用赋值的场景中容易出错。
    说明:扩展说一下PECS(Producer Extends Consumer Super) 原则,即频繁往外读取内容的,适合用<?extends T>,经常往里插入的,适合用<?super T>

  7. 【强制】在无泛型限制定义的集合赋值给泛型限制的集合时,在使用集合元素时,需要进行instanceof判断,避免抛出ClassCastException异常。
    说明:泛型是在JDK5后才出现,考虑到向前兼容,编译器是允许非泛型集合与泛型集合互相赋值。
    反例:

    ArrayList(10); notGenerics.add(new Object()); notGenerics.add(new
    Integer(1)); generics = notGenerics; //此处抛出 ClassCastException异常
    String string = generics.get(0); ```
    
  8. 【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用iterator方式,如果并发操作,需要对 iterator 对象加锁。
    正例:

    list.add("2"); Iterator<String>iterator = list.iterator(); while
    (iterator hasNext() { 	String item = iterator next(); 	if(删除元素的条件) {
    		iterator remove(); } ```
    
    <font color =A52A2A>反例:</font>
    
    ```java for(String item :list) { 	if ("1".equals(item)) {
    	listremove(item); 	} } ```
    
    <font color =#CD853F>说明:</font>反例中的执行结果肯定会出乎意料,试一下把"1"换成"2"
  9. 【强制】JDK7版本及以上,Comparator实现类要满足如下三个条件,不然Arrays.sort
    Collections.sort会抛 IllegalArgumentException 异常。
    说明:三个条件如下:
    (1)x,y的比较结果和y,x的比较结果相反。
    (2)x > yy > z,则x > z
    (3)x = y,则x,z比较结果和y,z比较结果相同。
    反例:下例中没有处理相等的情况,交换两个对象判断结果并不互反,不符合第一个条件,在实际使用中可能会出现异常。

    compare(Student o1, Student o2) { 		return o1.getld() > o2.getld() ?
    1 : -1; 	} }; ```
    
  10. 【推荐】泛型集合使用时,在JDK7及以上,使用 diamond语法或全省略。
    说明:菱形泛型,即diamond,直接使用<>来指代前边已经指定的类型。
    正例:

    // diamond方式,即<>
    HashMap<String, String> userCache = new HashMap<>(16); 
    //全省略方式  
    ArrayList<User> users = new ArrayList(10);
    
  11. 【推荐】集合初始化时,指定集合初始值大小。
    说明:HashMap 使用构造方法 HashMap(int initialCapacity)进行初始化时,如果暂时无法确定集合大小,那么指定默认值(16)即可。
    正例:initialCapacity =(需要存储的元素个数/负载因子)+1。注意负载因子(即loaderfactor)默认为0.75,如果暂时无法确定初始值大小,请设置为16(即默认值)。
    反例:HashMap需要放置1024个元素,由于没有设置容量初始大小,随着元素增加而被迫不断扩容,resize()方法总共会调用8次,反复重建哈希表和数据迁移。当放置的集合元素个数达千万级时会影响程序性能。

  12. 【推荐】使用 entrySet遍历 Map 类集合KV,而不是keySet方式进行遍历。
    说明:keySet 其实是遍历了2次,一次是转为Iterator对象,另一次是从 hashMap 中取出 key所对应的value。而entrySet只是遍历了一次就把keyvalue都放到了entry中,效率更高。如果是JDK8,使用Map.forEach方法。
    正例:values()返回的是V值集合,是一个list集合对象;keySet(返回的是K值集合,是一个Set集合对象;entrySet()返回的是K-V值组合的Set集合。

  13. 【参考】合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。
    说明:有序性是指遍历的结果是按某种比较规则依次排列的,稳定性指集合每次遍历的元素次序是一定的。如: ArrayList 是 order / unsort; HashMap 是 unorder / unsor; TreeSet 是 order / sort;

  14. 【参考】利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 Listcontains() 进行遍历去重或者判断包含操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值