Java编程规范

一、避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可

  • 通过一个引用去调用一个静态方法或静态变量的时候会加大JVM的性能消耗,对JVM来说,会先去检索一下堆中的信息,而且在解释过程中需要额外消耗一些资源的,如果用类名去调用会直接导入到方法区,可以避免堆空间的检索

二、所有的复写方法必须加@Override注解

三、相同参数类型,相同业务含义,才可以使用Java的可变参数,避免使用Object类型

  • 可变参数对JDK的编译JVM的解释都是一个比较大的消耗,它会在JVM下进行一个类似于数组的转换,在解释编译的时候要预留各种本地信息,如果一定要用可变参数 绝对不要写Object类型

四、外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么

  • 对于RPC开发和SOA架构模式来说,开发的每一块代码都可能是一个服务,服务需要对外暴露,服务发布之后,只要这个服务被使用了或者是被使用了,方法绝对不要改,可以重写或者重载来扩展服务能力

五、不能使用过时的类或方法

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

  • 推荐使用java.util.Objects包中的equals()方法进行比较

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

  • 只要不是8种基本数据类型进行比较的时候都使用equals方法
  • 只有在判断两个引用指向的是不是同一个 的时候 才能使用==
  • equals比较的是内容数据 ==比较的是内存地址

八、关于基本数据类型与包装数据类型的使用标准

  • 所有的pojo类属性必须使用包装数据类型
    • 数据库的查询接口可能是null,因为自动拆箱,用基本数据类型接受有风险,
  • PRC方法的返回值和参数必须使用包装数据类型
  • 所有的局部变量使用基本数据类型
    • 局部变量绝大多数情况下用作计算的,基本类型做计算是有天然优势的,不需要自动拆箱,自动封箱,避免出现空指针异常

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

  • VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
  • DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。
  • DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。数据对象,和数据库中的表一一对应

十、序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列化失败,如果完全不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值

十一、构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中

十二、pojo类必须写toString方法,如果继承了另一个pojo类,注意在前面加一个super.toString

  • 在方法执行抛出异常时,可以直接调用pojo的toString方法打印其属性值,便于排查问题

十三、使用索引访问用 String 的 split 方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛 IndexOutOfBoundsException 的风险

String str = "a,b,c,,"; 
String[] ary = str.split(","); 
// 预期大于 3,结果是 3
System.out.println(ary.length); 

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

  • 反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象,造成内存资源浪费
  • StringBuilder不会造成常量池空间中不必要数据的堆积,减少不必要对象的创建
  • 单线程时候使用:StringBuilder 多线程环境使用StringBuffer

十五、尽量不要用Object的clone方法来拷贝对象

  • 对象的clone方法默认是浅拷贝,若想实现深拷贝需要重写clone方法实现属性对象的拷贝

十六、类成员与方法访问控制从严:

  • 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。
  • 工具类不允许有 public 或 default 构造方法。
  • 类非 static 成员变量并且与子类共享,必须是 protected。
  • 类非 static 成员变量并且仅在本类使用,必须是 private。
  • 类 static 成员变量如果仅在本类使用,必须是 private。
  • 若是 static 成员变量,必须考虑是否为 final。
  • 类成员方法只供类内部调用,必须是 private。
  • 类成员方法只对继承类公开,那么限制为 protected。

集合处理

一、关于hashCode和equals的处理

  • 只要重写 equals,就必须重写 hashCode。
  • 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须重写这两个方法。
  • 如果自定义对象作为 Map 的键,那么必须重写 hashCode 和 equals

说明:String 重写了 hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用

二、在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均会产生 ConcurrentModificationException 异常。

标题三、使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()。

List<String> list = new ArrayList<String>(2); 
list.add("guan");    
list.add("bao"); 
String[] array = new String[list.size()]; 
array = list.toArray(array); 
  • 直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误

四、使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

  • 说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

    String[] str = new String[] { “you”, “wu” };
    List list = Arrays.asList(str);

  • 第一种情况:list.add(“yangguanbao”); 运行时异常。

  • 第二种情况:str[0] = “gujin”; 那么 list.get(0)也会随之修改

五、泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用 add 方法,而<? super T>不能使用 get 方法,作为接口调用赋值时易出错。

  • 说明:扩展说一下 PECS(Producer Extends Consumer Super)原则:第一、频繁往外读取内容的,适合用<? extends T>。第二、经常往里插入的,适合用<? super T>。

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

七、在 JDK7 版本及以上,Comparator 要满足如下三个条件,不然 Arrays.sort,Collections.sort 会报 IllegalArgumentException 异常

  • 一定要计算好排序规则

八、集合初始化时,指定集合初始值大小。

  • 说明:HashMap 使用 HashMap(int initialCapacity) 初始化,
  • 正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。
  • 反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容量 7 次被迫扩大,resize 需要重建 hash 表,严重影响性能

九、使用 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 值组合集合。

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

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

十一.合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。

  • 说明:有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次序是一定的。如:ArrayList 是 order/unsort;HashMap 是 unorder/unsort;TreeSet 是order/sort。
  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值