Java异常分类

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

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

Java 异常处理

上图列出了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日志门面方便的切换具体的日志实现。

相关文章:

猜你喜欢
  • 2021-11-24
  • 2022-02-22
  • 2021-11-05
  • 2021-09-24
  • 2021-04-02
  • 2021-05-10
相关资源
相似解决方案