Java异常总结

在谈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

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要求你对这些不可避免的异常作强制的处理。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容