【Java梳理】异常Exception

异常是软件系统不可避免的的问题,软件系统在运行中难免发生不可预知的错误,为了避免异常造成软件自动停止运行造成损失,软件开发语言一般提供异常处理机制。
在Java中定义了两种程序运行发生的错误,它们是Error和Exception,它们都继承自Throwable类。从设计上来讲Error代表的是不能有程序自己处理的异常,比如内存溢出等。
Exception代表的是检查异常,即再编程时必须显示处理的异常,要么try-catch,要么抛出方法外,这是在编译器检查的。
区别于Exception,它的子类RuntimeException是运行时异常(非检查),即不是必需写代码处理它,也可以编译通过。

抛出一个异常;
throw new Throwable("Throwable");
throw new Error("error");
throw new Exception("Exception");
throw new RuntimeException("RuntimeException");

在throw 一个异常之后,throw 语句后面的代码不会再运行,立即退出try{}块或者方法(没被try包裹时,方法不会有返回值,而是把异常沿着函数栈往上抛出,直到被处理)。

指定方法抛出异常

public void method() throws Exception {
        throw new Exception("exception by method");
    }

异常的处理。可以使用try-catch-finally结构来处理异常,如

        try {
            HelloWorld helloWorld = new HelloWorld();
            helloWorld.method();  //这里会抛出异常
        } catch (Throwable t) {
            System.out.println(t.getMessage());
        }finally {
            System.out.println("finally");
        }

在上面的代码中,try表示监控异常代码,catch块是处理异常的代码,在发生异常时才执行。finally 不管异常有没有发生都会在try和catch之后执行。
其中try可以指定多个异常,也可以对不同的异常分别处理

try {
            HelloWorld helloWorld = new HelloWorld();
            helloWorld.method();
        } catch (RuntimeException | Error e) {  //处理多种异常
            System.out.println(e.getMessage());
        }catch (Exception e1){          //单独处理Exception 的情况
            System.out.println(e1.getMessage());
        }
        finally {
            System.out.println("finally");
        }

比较值得注意的是当try块或者catch块中有return语句的情况下,代码的执行过程,下面以实例说明

public static void main(String[] args) {
        System.out.println(testEx());
    }

    public static String testEx() {
        try {
            method();
            return "try";
        } catch (Exception e) {
            return "catch";
        } finally {
            return "finally";
        }
    }

    public static void method() {
        throw new RuntimeException("exception by method");
    }

输出结果为
finally

这里要注意的是,即使在try块或者catch块 有return语句,finally 块还是会执行,这时之前的return结果是被缓存着的。如果finally 中有return语句,那么直接return finally 中的结果。

自定义异常:
虽然Java提供了足够多的异常类型,但是自定义异常在业务当中是非常常见的。一般的,我们会实现继承自Exception,RuntimeException的类型,它们和它们的父类有着一样的特性。

异常抑制:
之前提到finally 中的return会替代try catch块中的return。其实finally 中抛出的异常也会抑制后两者抛出的异常,在调用者那里捕获的是finally 的异常,try catch块中的异常好像消失了。

 public static void main(String[] args) {
        try {
            testEx();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static String testEx() {
        Exception ex = null;
        try {
            throw new RuntimeException("ex in try");
        } catch (Exception e) {
            ex = e;
        } finally {
            RuntimeException runtimeException =  new RuntimeException("ex in finally");
            runtimeException.addSuppressed(ex);  //添加被抑制的异常
            throw runtimeException;
        }
    }

观察输出:

java.lang.RuntimeException: ex in finally
    at helloworld.HelloWorld.testEx(HelloWorld.java:27)
    at helloworld.HelloWorld.main(HelloWorld.java:14)
    Suppressed: java.lang.RuntimeException: ex in try
        at helloworld.HelloWorld.testEx(HelloWorld.java:23)
        ... 1 more

可以发现,mian方法捕捉到的异常是finally产生的,这里我们可以把被抑制的异常手动添加,这样不会丢失有价值的异常信息。

Java7新特性 try with resource
当使用需要关闭的一些资源,比如FileStream这些流,往往要在使用完成之后关闭它,一般的实践是在finally 块中将它们关闭,但是这样会导致代码量相对增多。Java7提供了 try with resource的写法,Java会自动帮我们关闭这些资源,即会自动调用对象的close()方法。
一个 try-with-resources 语句可以像普通的 try 语句那样有 catch 和 finally 块。在try-with-resources 语句中,任意的 catch 或者 finally 块都是在声明的资源被关闭以后才运行。

你可能感兴趣的:(【Java梳理】异常Exception)