Exception best practice
http://www.wikijava.org/wiki/10_best_practices_with_Exceptions
10 best practices with Exceptions
From WikiJava
这篇文章列举了十个Java里使用Exception的最佳实践
Exception是一个能打断程序正常逻辑的event. Exception不一定代表一个错误,但是JAVA里一般用Exception代表一个错误
如果你不知道Exception是神马东西,看Sun公司提供的这个文档: tutorial about exceptions.
Relevancy
函数只应该跑出和他本身有关系的Exception
看这个构造函数
java.io.FileInputStream.FileInputStream(String name) throws FileNotFoundException
这个函数打开一个文件,读取数据,所以它抛出FileNotFoundException就很合理. 如果它抛出IndexOutOfBoundsException那就不合理了
Encapsulation
Relevancy后面就得提这个:Encapsulation. 就是说把异常包装成另外一个异常.
也就是说如果你的函数调用了另一个函数,而那个函数抛出了一个异常,而且那个异常是一个很general的异常,那你可能就得考虑把这个异常包装一下再抛出去
try { return new FileOutputStream(fileName); } catch (FileNotFoundException e) { throw new ActionException(e); }
这个函数接受了一个FileOutputStream 异常, 然后把它包装成ActionException, 然后抛出.
这样做有好处:
- 符合Relevancy的原则,也就是说我这个函数可没抛出那个很general的异常
- Debug的时候也能多一些信息(因为包装过了么)
Reason
异常必须说明自己被抛出的原因,有两种方式:
- 每次都抛出不同种类的异常
- 创建一个很general的异常然后用字符串描述之
前者要求你创建好多异常类,后者Catch到以后不好处理. 怎么做好呢,就是折中.
如果你想用不同的方法来处理异常那你就创建新的异常类, 反之你就考虑用一个比较一般的异常.
Exception names
异常类的名字必须有意义, 比如java.io.FileNotFoundException.
java.lang.Exception 是最一般的异常类,它有它的用处,但是你别直接抛出它,因为它的名字不能提供任何其他特定信息. 作者的习惯是即使是一般的异常类,也自己创建一个,给自己的特定代码使用.这样你看到这个异常你就知道你的那部分代码有问题了.
Balance what you catch
catch 也有两种写法:
- 一个catch抓住所有类型的异常
} catch (Throwable e) { throw new CommandExecutorException(e); }
- 每个异常都写一个catch
} catch (ClassCastException e1) { ... } catch (FileNotFoundException e) { ... } catch (IOException e) { ... }
这个问题其实不难, 关键就看你是不是需要对每种异常区别处理
Scoping
try 包含的代码多长呢, 你可以整个函数就写一个try,也可以每行可能跑异常的代码都写一个try. 两者当然各有优缺点.
有一些指导原则:
- 可以用
try-blocks来规范变量的作用域 - 如果你有一个变量只是在一下段代码里使用,可以把它放在try里面
- 用try来分隔你的代码
- 把一大段代码用try分隔成几个逻辑小块, 这样代码易读性好
- 用多个try能使得你处理异常的粒度比较小
- 这种情况下你可以用很多try block. 如果你用一个大的try block,你的代码就不容易读到是哪块代码抛出的哪个异常
- 考虑代码的大小
- 如果你有一个函数很大,一屏幕也装不下(应该避免这种), 那么用try block分割代码也不错
- 抛出的异常的数量
- 如果你有一个很大的try block,那么这一大块抛出的异常数量可能就比较多,那你就得弄多个catch, catch连起来也很难看
Use Finally
Finally用来清理资源什么的很有用
FileWriter output= null; try { output = new FileWriter(file); output.write(stringBuffer.toString()); System.out.println("file " + path + filename + " written"); } catch (IOException e) { e.printStackTrace(); } finally { try { output.close(); } catch (Throwable e) { e.printStackTrace(); } }
上面这里看到finally里又有try catch, 发生了嵌套. 如果你这样写,那就有点危险了
try { output.close(); } catch (IOException e) { e.printStackTrace(); }
因为这个catch和外面那个catch (IOException e) 有冲突 (为毛?我不懂,谁给我解释解释)
Throw only Exceptions
JAVA里面只要继承java.lang.Throwable,你就能抛出它. 但是记住throwable就是用来抛出错误和异常的,如果你用throwable做其他目的,那么别人看你的代码就会一头雾水了,所以你最好别这么干
Throw early catch late
这是异常处理里面最著名的定律. 意思是如果有一个异常你就应该尽早抛出,然后尽量晚,直到你得到所有信息能处理这个异常的时候才处理它.
这里的意思是你应该在底层的函数里就抛出异常,比如检查null或什么东西. 然后让这个异常爬到栈的顶层去处理,比如在GUI层让用户决定如何操作,甚至是在main里面让程序退出之类的
Add validation
检查输入(参数什么的),如果不对就抛出异常.
if ( null == variable || variable.isEmpty()){ throw new blahException("the variable cannot be null at this point"); }
不过也不是每个参数都必须检查,这个要具体问题具体分析.
浙公网安备 33010602011771号