Java 异常处理

Java异常分类

Java 中的异常都继承自 Throwable 类。

Throwable 分为两大类:Error 与 Exception。Error 一般表示统错误,如栈溢出、堆溢出等等,一般不用我们关心。Exception 是程序本身可以捕获并且可以处理的异常,是我们需要重点关注的。

上图列出了 Java 中常见的异常,仍有许多异常没有列出。比如 IOException 下就有几十种异常。

Exception 类分为运行时异常编译异常

  • 运行时异常(RuntimeException):也称非检查性异常(unchecked exception),表示程序在运行期间可能出现的错误。最典型的就是空指针异常(NullPointerException)、数组下标越界。在程序中可以选择捕获处理,也可以不处理。运行时异常可以通过预先检查进行规避,而不应该通过 catch 来处理(阿里巴巴Java开发手册)。
  • 编译异常:也称检查性异常(checked exception)。Exception 中除 RuntimeException 及其子类之外的异常都属于编译异常。在程序中必须对该类型异常进行处理,否则编译不通过。处理的方式包括向上抛出异常或 try-catch 捕获异常。

自定义异常

如果因业务需要或已有的异常无法表示,这时可以自定义异常。自定义异常的方式非常简单。

class MyException extends Exception {

    private static final long serialVersionUID = 1L;

    public MyException(String msg) {
        super(msg);
    }

}

public class ExceptionTest {
    public void f() throws MyException {
        throw new MyException("MyException in f()");
    }

    public static void main(String[] args) {
        ExceptionTest test = new ExceptionTest();
        try {
            test.f();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }
}

输出结果:

test.MyException: MyException in f()
	at test.ExceptionTest.f(ExceptionTest.java:15)
	at test.ExceptionTest.main(ExceptionTest.java:21)

e.printStackTrace() 将此异常及其追踪输出至标准错误流


异常处理

从 Java 7 开始,catch 语句可以一次捕获多个异常,称为 multi-catch,如下所示:

public class ExceptionTest {
    public void f() throws MyException, SecurityException, IOException {
        throw new MyException("MyException in f()");
    }

    public static void main(String[] args) {
        ExceptionTest test = new ExceptionTest();
        try {
            test.f();
        } catch (SecurityException | IOException | MyException e) {
            e.printStackTrace();
        }
    }
}

try-with-resources

从 java 1.7 开始,使用 try-with-resources 可以自动关闭实现了 AutoCloseable 或者 Closeable 接口的资源,无论它是正常执行还是抛出异常。

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

try-with-resources 语句可以同时有 catch 块和 finally 块。这种情况下,catch 块和 finally 块会在 resources 都关闭后再运行。

在使用finally块中的场景中,如果 try 和 finally 块中的语句都抛出异常,最终抛出的是 finally 中的异常,try 中的异常会被抑制。

在使用 try-with-resources 的场景中,如果 try 和 try-with-resources 中的语句都抛出异常,最终抛出的是 try 中的异常,try-with-resources 中的异常会被抑制。

可以通过 Throwable.getSuppressed() 方法获得被抑制的异常。

public class SuppressedExceptions {

    static class CloseExceptions implements Closeable {
        @Override
        public void close() throws IOException {
            throw new IOException("Exception from CloseExceptions.close");
        }
    }

    public static void main(String[] args) {
        try (CloseExceptions ce = new CloseExceptions()) {
            throw new IOException("Exception from try block!");
        } catch (Exception e) {
            System.out.println(Arrays.toString(e.getSuppressed()));
        }
    }
}

输出结果:

[java.io.IOException: Exception from CloseExceptions.close]

虽然我们可以用异常的父类代替多个子类,如下所示:

try {
    test.f();
} catch (Throwable e) {
    e.printStackTrace();
}

但不推荐这样做,不同的异常代表着不同的错误,分别处理有助于故障排查与处理。


将异常通过日志输出

class MyException extends Exception {

    private static final long serialVersionUID = 1L;
    Logger log = Logger.getLogger(this.getClass().getName());

    public MyException(String msg) throws SecurityException, IOException {
        StringWriter trace = new StringWriter();
        printStackTrace(new PrintWriter(trace));
        Handler handler = new FileHandler("e:/info.txt");
        log.addHandler(handler);
        log.warning(trace.toString());
    }

}

public class ExceptionTest {
    public void f() throws MyException, SecurityException, IOException {
        throw new MyException("MyException in f()");
    }

    public static void main(String[] args) throws SecurityException, IOException {
        ExceptionTest test = new ExceptionTest();
        try {
            test.f();
        } catch (MyException e) {
            System.out.println("caught it!");
        }
    }
}

运行后异常将显示在控制台,并输出到 info.txt 文件中。

此处用的日志系统是 Java 自带的 logging 工具。事实上现在有很多优秀的日志框架实现,如 Log4j、Logback 等,可以用 SLF4J 日志门面方便的切换具体的日志实现。

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页