java中的异常的超类是java.lang.Throwable(后文省略为Throwable),它有两个比较重要的子类,java.lang.Exception(后文省略为Exception)和java.lang.Error(后文省略为Error),其中Error由JVM虚拟机进行管理,如我们所熟知的OutOfMemoryError异常等,所以我们本文不关注Error异常,那么我们细说一下Exception异常。
非受检异常(unchecked Exception)
- Exception异常的子类RuntimeException或其他继承自RuntimeException的子类
受检异常(checked Exception)
- 其他继承自Exception异常的子类
如何选择异常
如果调用者可以处理,并且你也希望调用者进行处理,那么就要抛出受检异常,提醒调用者在使用你的方法时,考虑到如果抛出异常时如果进行处理,相似的,如果在写某个方法时,你认为这是个偶然异常,理论上说,你觉得运行时可能会碰到什么问题,而这些问题也许不是必然发生的,也不需要调用者显示的通过异常来判断业务流程操作的,那么这时就可以使用一个RuntimeException这样的非受检异常.
什么时候才需要抛异常
如果你觉得某些”问题”解决不了了,那么你就可以抛出异常了。比如,你在写一个service,其中在写到某段代码处,你发现可能会产生问题,那么就请抛出异常吧
应该抛出怎样的异常
先从受检异常说起,比如说有这样一个业务逻辑,需要从某文件中读取某个数据,这个读取操作可能是由于文件被删除等其他问题导致无法获取从而出现读取错误,那么就要从redis或mysql数据库中再去获取此数据,参考如下代码,getKey(Integer)为入口程序.
public String getKey(Integer key){
String value;
try {
InputStream inputStream = getFiles("/file/nofile");
//接下来从流中读取key的value指
value = ...;
} catch (Exception e) {
//如果抛出异常将从mysql或者redis进行取之
value = ...;
}
}
public InputStream getFiles(String path) throws Exception {
File file = new File(path);
InputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
} catch (FileNotFoundException e) {
throw new Exception("I/O读取错误",e.getCause());
}
return inputStream;
}
解析:
- 受检异常可以控制义务逻辑,切记尽量不要这样使用,这样将异常的作用扩大化,会导致代码复杂程度的增加,耦合性会提高,代码可读性降低等问题
- 如果调用者调用出错后,一定要让调用者对此错误进行处理才可以,满足这样的要求时,我们才会考虑使用受检异常。
接下来,我们来看一下非受检异常(RuntimeException),对于RuntimeException这种异常,我们其实很多见,比如java.lang.NullPointerException/java.lang.IllegalArgumentException等,那么这种异常我们时候抛出呢?当我们在写某个方法的时候,可能会偶然遇到某个错误,我们认为这个问题时运行时可能为发生的,并且理论上讲,没有这个问题的话,程序将会正常执行的时候,它不强制要求调用者一定要捕获这个异常,此时抛出RuntimeException异常
public void test() {
myTest.getFiles("");
}
public File getFiles(String path) {
if(null == path || "".equals(path)){
throw new NullPointerException("路径不能为空!");
}
File file = new File(path);
return file;
}
解析:
如果调用者调用getFiles(String)的时候如果path是空,那么就抛出空指针异常(它是RuntimeException的子类),调用者不用显示的进行try…catch…操作进行强制处理.这就要求调用者在调用这样的方法时先进行验证,避免发生RuntimeException
总结出一个结论: RuntimeException异常和受检异常之间的区别就是:是否强制要求调用者必须处理此异常,如果强制要求调用者必须进行处理,那么就使用受检异常,否则就选择非受检异常(RuntimeException)。一般来讲,如果没有特殊的要求,我们建议使用RuntimeException异常。