在谈Java异常的时候,好多其他文章上来就谈Java中异常继承了什么,分什么...
我们不妨先来谈谈,如果Java没有异常怎么办?
跟同事讨论这个问题的时候,很多同事的第一反应就是语塞。因为针对异常的处理,大家都太习惯了。习以为常,自然没有了思考这个问题的习惯。
如果不使用Java中的异常机制,其他的语言有些使用error code的方式。在程序异常的时候返回异常码,再有程序员根据异常码手动增加判断来处理。
而Java中则使用try-catch机制,用try-cath机制的一个好处是把异常代码与业务代码分离。当然不好的一个地方就是有很多的模板代码。
public class ReadFile {
public static void main(String[] args) {
File file = new File("D://test.txt");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
FileChannel channel = fileInputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(128);
int i = channel.read(byteBuffer);
while (i != -1) {
byteBuffer.flip(); // 切换到读模式
// byteBuffer操作
byteBuffer.clear();
i = channel.read(byteBuffer);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
一个简单的文件操作包含了大量的 try-catch,还要把 FileInputStream 变量的定义抽到 try的外层去定义,否则在 finally不能关闭。在随后的JDK7中引入的try-with-resources使关闭流的操作简单点。但由上可见,try-catch机制还是会导致很多的模板代码。
接下来我们聊一下Java的异常的具体情况:
Exception 和 Error是继承了 Throwable 类
Throwable类中的注释:
Only objects that are instances of this
class (or one of its subclasses) are thrown by the Java Virtual Machine or
can be thrown by the Java {@code throw} statement. Similarly, only
this class or one of its subclasses can be the argument type in a
{@code catch} clause.
意思是:只有Throwable,或其子类可以被Jvm抛出。类似,也只有Throwable还有其子类可以作为catch 的参数。
For the purposes of compile-time checking of exceptions, {@code
Throwable} and any subclass of {@code Throwable} that is not also a
subclass of either {@link RuntimeException} or {@link Error} are
regarded as checked exceptions.
基于编译时期检查异常的目的,Java会将Throwable(包括其子类)中,所有非 RuntimeException,或非Error的子类都视为受检异常。
换句话说,Exception的子类除RuntimeException是非受检的异常外。其他均为受检异常。
这里用代码说明一下什么是受检异常,什么是非受检异常。
这里的 throwCheckedException为什么提示错误呢?
因为IOException并不是RuntimeException的子类。
正常代码如下
public class ThrowableDemo {
public void throwError(){
throw new NoClassDefFoundError();
}
public void throwRuntimeException(){
throw new NullPointerException();
}
public void throwCheckedException() throws IOException {
throw new IOException();
}
/* public void throwCheckedException() {
try {
throw new IOException();
} catch (IOException e) {
e.printStackTrace();
}
}*/
public static void main(String[] args) {
ThrowableDemo throwableDemo = new ThrowableDemo();
try {
throwableDemo.throwCheckedException();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对于受检异常,可以用try-catch处理。也可以选择继续抛出。
非受检异常:Java不在编译期间强制要求你处理
受检异常:Java要求在编译期间强制要求你处理
因此针对以上说的IOException需要你自己处理。
注意: 非受检异常都是RuntimeException(或其子类)。
对于RuntimeException如:NullPointerException,IndexOutOfBoundsException,ClassCastException这些大家比较熟悉的异常有一个共通点,就是都可以由程序员在编程的层面避免的。
NullPointerException: 使用前判断非空。
IndexOutOfBoundsException:检查数组索引是否存在。
ClassCastException: 转换类型前作判断。
而非RuntimeException则是不能通过程序来避免的。
如IOException:读取的文件资源在运行的时候不存在。
所以Java要求你对这些不可避免的异常作强制的处理。