Java代码健壮性规范

一、常见错误处理篇

1、对于NULL和空的判断。对于可能出现空值或者null值的类或者参数一定要做健壮性判断。
2、对于返回值一律不准返回NULL,可以使用空字符串、空容器的方式返回
3、对于浮点数,必须对精度进行规范,不可返回不限有效小数位的值
4、使用"const".eqauls(variable)代替 variable.eqauls("const") 避免 null point exception
3、在进行复杂查询语句的拼接的时候,建议加上"where 1=1",当然在不考虑数据库的性能情况下.
4、在进行数据库操作的时候用PreparedStatement代替Statement,这样可以避免在拼接字符串的时候出现单引号过多的情况
5、使用带参构造函数时,必须同时写上无参构造函数,避免编译异常。在构造器内部,只进行那些将对象设为正确状态所需的工作,尽可能地避免调用其他方法
6、禁止使用构造方法 BigDecimal(double):存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
反例

BigDecimal value = new BigDecimal(0.1D); // 0.100000000000000005551115...

正例

BigDecimal value = BigDecimal.valueOf(0.1D); // 0.1

7、小心String.split(String regex) 字符串 String 的 split 方法,传入的分隔字符串是正则表达式!部分关键字(比如.| 等)需要转义。
反例

"a.ab.abc".split("."); // 结果为[]
"a|ab|abc".split("|"); // 结果为["a", "|", "a", "b", "|", "a", "b", "c"]

正例

"a.ab.abc".split("\\."); // 结果为["a", "ab", "abc"]
"a|ab|abc".split("\\|"); // 结果为["a", "ab", "abc"]

二、异常处理篇

1、在使用数据库操作的时候尽量多用finally语句,进行资源的释放。

try{
    ...
}catch(Exception e){
    ...
} finally{
 if (conn != null) {
     conn.colse();
     conn == null
 }
}

2、在进行多异常捕获的时候,最后建议加上Exception异常做没有考虑到的异常捕获,比如

try{
    ...
}catch (OtherException e){
    ...
}catch(Exception e){
    ...
} finally{
 if (conn != null) {
    conn.colse();
    conn == null;
    }
}

三、性能优化篇

1、字串的开销,字符串处理频率高的情况,要多用StringBuffer(字串缓冲)将String = “str”+”str2”;使用StringBuffer str = newStringBuffer(“str”);str.append(“str2”)代替
2、同步方法(synchronized修饰方法)要尽量细粒度更高,避免在JDK解释器中调用耗时过多。
3、避免重复新建对象,如果有重复利用可以考虑对该对象初始化
4、使用Integer.valueOf()代替new Integer();
5、可以用for(int i= 100;i>0;i--;)去代替for(int i = 0;i <100;i++)这样可以提高程序的运行速度,对于for循环for(int i=o;i<list.size();i++) 显然不如 for(int i=o;list!=null&&i<list.size();i++)健壮
6、在表单取值的时候,多使用String A = B.trim();来去空格
7、把某非String类型转换成String类型的,大多用.toString();但可以用String.valueof(...);
8、类之间耦合度过高,多考虑使用内部类
9、尽量使用interfaces,少使用abstract类。
10、警惕”过度分析”。
11、警惕”过早优化”。
12、多使用MessageFormat类,utils类
13、需要 Map 的主键和取值时,应该迭代 entrySet():当循环中只需要 Map 的主键时,迭代 keySet() 是正确的。但是,当需要主键和取值时,迭代 entrySet() 才是更高效的做法,比先迭代 keySet() 后再去 get 取值性能更佳。

Map<String,String> map = ...;
for (Map.Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
}

14、频繁调用 Collection.contains 方法请使用 Set:在 java 集合类库中,List 的 contains 方法普遍时间复杂度是 O(n) ,如果在代码中需要频繁调用 contains 方法查找数据,可以先将 list 转换成 HashSet 实现,将 O(n) 的时间复杂度降为 O(1) 。
反例

ArrayList<Integer> list = otherService.getList();
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    // 时间复杂度O(n)
    list.contains(i);
}

正例

ArrayList<Integer> list = otherService.getList();
Set<Integer> set = new HashSet(list);
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    // 时间复杂度O(1)
    set.contains(i);
}

15、集合初始化尽量指定大小:java 的集合类用起来十分方便,但是看源码可知,集合也是有大小限制的。每次扩容的时间复杂度很有可能是 O(n) ,所以尽量指定可预知的集合大小,能减少集合的扩容次数。
反例

int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>();
for (int i : arr) {
    list.add(i);
}

正例

int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>(arr.length);
for (int i : arr) {
    list.add(i);
}

16、应该使用Collection.isEmpty()检测空:使用 Collection.size() 来检测空逻辑上没有问题,但是使用 Collection.isEmpty()使得代码更易读,并且可以获得更好的性能。任何 Collection.isEmpty() 实现的时间复杂度都是 O(1) ,但是某些 Collection.size() 实现的时间复杂度可能是 O(n) 。

反例

if (collection.size() == 0) {...}

正例

if (collection.isEmpty()) {...}

17、List 的随机访问
数组和链表的区别:数组的随机访问效率更高。当调用方法获取到 List 后,如果想随机访问其中的数据,并不知道该数组内部实现是链表还是数组,怎么办呢?可以判断它是否实现 RandomAccess 接口。

// 调用服务获取到list
List<Integer> list = otherService.getList();
if (list instanceof RandomAccess) {
    // 内部数组实现,可以随机访问
    System.out.println(list.get(list.size() - 1));
} else {
    // 内部可能是链表实现,随机访问效率低
}

四、编码规范篇:

1、给每个if(condition){}都加上大括号,即使里面只有一句话,加强程序的可读性
2、能用常量的东西都要用常量来完成,避免使用硬编码,增加可维护性质。比如少用 String str = "123"使用private static final CONST = "123" ; String str = CONST;
3、避免使用”魔术数字”
4、用继承及方法覆盖来表示行为间的差异,而用字段表示状态间的区别。
5、避免同路径下的类名重名

附录1:常见错误总结:

1、java.lang.NullpointerException(空指针异常)
原因:这个异常经常遇到,异常的原因是程序中有空指针,即程序中调用了未经初始化的对象或者是不存在的对象。经常出现在创建对象,调用数组这些代码中,比如对象未经初始化,或者图片创建时的路径错误等等。对数组代码中出现空指针,是把数组的初始化和数组元素的初始化搞混淆了。数组的初始化是对数组分配空间,而数组元素的初始化,是给数组中的元素赋初始值

2、 java.lang.ClassCastException(类型转换异常)
原因:当试图将一个String类型数据转换为指定的数字类型,但该字符串不满足数值型数据的要求时,就抛出这个异常。例如将String类型的数据”123456”转换为数值型数据时,是可以转换的的。但是如果String类型的数据中包含了非数字型的字符,如123*56,此时转换为数值型时就会出现异常。系统就会捕捉到这个异常,并进行处理

3、java.lang.ClassNotFoundException(指定的类不存在)
原因:是因为类的名称和路径不正确,通常都是程序试图通过字符串来加载某个类的时候可能会引发异常。例如:调用Class.forName()、或者调用ClassLoad的finaSystemClass()、或者是LoadClass()时出现异常

4、java.lang.IndexOutOfBoundsException(数组下标越界异常)
原因:查看程序中调用的数组或者字符串的下标值是不是超出了数组的范围,一般来说,显示调用数组不太容易出这样的错,但隐式调用就有可能出错了,还有一种情况,是程序中定义的数组的长度是通过某些特定方法决定的,不是
事先声明的,这个时候可以先查看一下数组的length,以免出现这个异常

5、java.lang.IllegalArgumentException(方法的参数错误)
例如g.setColor(int red,int green,int blue)这个方法中的三个值,如果有超过255的会出现这个异常,如果程序中存在这个异常,就要去检查一下方法调用中的参数传递或参数值是不是有错

6、java.lang.IllegalAccessException(没有访问权限)
当程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常。如果程序中用了Package的情况下有可能出现这个异常

7、java.lang.ArithmeticException(数学运算异常)
当数学运算中出现了除以零这样的运算就会出这样的异常。

8、java.lang.ClassCastException(数据类型转换异常)
当试图将对某个对象强制执行向下转换,但该对象又不可转换或又不可转换为其子类的实例时将出现该异常

9、 java.lang.FileNotFoundException(文件未找到异常)
当程序打开一个不存在的文件来进行读写时将会引发该异常。该异常由FileInputStream,FileOutputStream,RandomAccessFile的构造器声明抛出,即使被操作的文件存在,但是由于某些原因不可访问,比如打开一个只有只读权限的文件并向其中写入数据,以上构造方法依然会引发异常

10、java.lang.ArrayStoreException(数组存储异常)
当试图将类型为不兼容类型的对象存入一个Object[]数组时将引发异常

11、java.lang.NoSuchMethodException(方法不存在异常)
当程序试图通过反射来创建对象,访问(修改或读取)某个方法,但是该方法不存在就会引发异常。

12、 java.lang.EOFException(文件已结束异常)
当程序在输入的过程中遇到文件或流的结尾时,引发异常。因此该异常用于检查是否达到文件或流的结尾

13、java.lang.InstantiationException(实例化异常)
当试图通过Class的newInstance()方法创建某个类的实例,但程序无法通过该构造器来创建该对象时引发。Class对象表示一个抽象类,接口,数组类,基本类型 。该Class表示的类没有对应的构造器。

14、java.lang.InterruptedException(被中止异常)
当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。

15、java.lang.CloneNotSupportedException (不支持克隆异常)
当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常

16、java.lang.OutOfMemoryException (内存不足错误)
当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误

17、java.lang.NoClassDefFoundException (未找到类定义错误)
当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误

附录2:异常处理规范

1、不要丢弃异常,捕获异常后需要进行相关处理。如果用户觉得不能很好地处理该异常,就让它继续传播,传到别的地方去处理,或者把一个低级的异常转换成应用级的异常,重新抛出
2、catch语句应该指定具体的异常类型。不能把不该捕获的异常也捕获了
3、在finally里面释放资源。如果finally里面也会抛出异常,也一样需要使用try…catch处理
4、不要把大量的代码塞在try…catch块里面,分离各个可能出现异常的语句并分别捕获异常
5、由于异常可能导致输出的数据不完整,因此用户需要作出相对应的处理,至少应该提示该数据的不完整

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值