跳至主要內容

03. Java链式异常

LiuSongLing大约 3 分钟javajavaexception

在本文中,我们将非常简要地了解什么是异常,并深入讨论Java中的链式异常。

简而言之,异常是扰乱程序正常执行流程的事件。现在让我们看看如何将异常链接起来,以从中获得更好的语义。

1.链式异常

链式异常有助于识别一个异常导致应用程序中另一个异常的情况。

例如,考虑一种方法,该方法由于试图除以零而抛出ArithmeticException,但异常的实际原因是I/O错误,导致除数为零。

该方法将向调用者抛出ArithmeticException。来电者不知道异常的实际原因。在这种情况下使用ChainedException。

这个概念是在JDK 1.4中引入的。

让我们看看Java如何支持链式异常。





2.可抛类

可抛类有一些构造函数和方法来支持链式异常。首先,让我们看看构造函数。

  • Throwable(Throwable cause)-Throwable有一个参数,它指定了异常的实际原因。
  • Throwable(String desc,Throwable cause)-此构造函数也接受带有异常实际原因的异常描述。

接下来,让我们看看这个类提供的方法:

  • getCause()方法-此方法返回与当前异常相关联的实际原因。
  • initCause()方法-它通过调用异常设置一个底层原因。

3.示例

现在,让我们看看示例,我们将设置自己的异常描述并抛出一个链式异常:

public class MyChainedException {

    public void main(String[] args) {
        try {
            throw new ArithmeticException("Top Level Exception.")
              .initCause(new IOException("IO cause."));
        } catch(ArithmeticException ae) {
            System.out.println("Caught : " + ae);
            System.out.println("Actual cause: "+ ae.getCause());
        }
    }    
}

正如猜测的那样,这将导致:

Caught: java.lang.ArithmeticException: Top Level Exception.
Actual cause: java.io.IOException: IO cause.

3.1 不连锁异常

首先,我们将创建一系列例外:

class NoLeaveGrantedException extends Exception {

    public NoLeaveGrantedException(String message, Throwable cause) {
        super(message, cause);
    }

    public NoLeaveGrantedException(String message) {
        super(message);
    }
}

class TeamLeadUpsetException extends Exception {
    // Both Constructors
}

现在,让我们开始在代码示例中使用上述异常:

public class MainClass {

    public void main(String[] args) throws Exception {
        getLeave();
    }

    void getLeave() throws NoLeaveGrantedException {
        try {
            howIsTeamLead();
        } catch (TeamLeadUpsetException e) {
            e.printStackTrace();
            throw new NoLeaveGrantedException("Leave not sanctioned.");
        }
    }

    void howIsTeamLead() throws TeamLeadUpsetException {
        throw new TeamLeadUpsetException("Team Lead Upset");
    }
}

在上面的示例中,日志将看起来像这样:

com.baeldung.chainedexception.exceptions.TeamLeadUpsetException: 
  Team lead Upset
    at com.baeldung.chainedexception.exceptions.MainClass
      .howIsTeamLead(MainClass.java:46)
    at com.baeldung.chainedexception.exceptions.MainClass
      .getLeave(MainClass.java:34)
    at com.baeldung.chainedexception.exceptions.MainClass
      .main(MainClass.java:29)
Exception in thread "main" com.baeldung.chainedexception.exceptions.
  NoLeaveGrantedException: Leave not sanctioned.
    at com.baeldung.chainedexception.exceptions.MainClass
      .getLeave(MainClass.java:37)
    at com.baeldung.chainedexception.exceptions.MainClass
      .main(MainClass.java:29)

3.2 连锁异常

链式异常:

public class MainClass {
    public void main(String[] args) throws Exception {
        getLeave();
    }

    public getLeave() throws NoLeaveGrantedException {
        try {
            howIsTeamLead();
        } catch (TeamLeadUpsetException e) {
             throw new NoLeaveGrantedException("Leave not sanctioned.", e);
        }
    }

    public void howIsTeamLead() throws TeamLeadUpsetException {
        throw new TeamLeadUpsetException("Team lead Upset.");
    }
}

让我们看看通过链式异常获得的日志:

Exception in thread "main" com.baeldung.chainedexception.exceptions
  .NoLeaveGrantedException: Leave not sanctioned. 
    at com.baeldung.chainedexception.exceptions.MainClass
      .getLeave(MainClass.java:36) 
    at com.baeldung.chainedexception.exceptions.MainClass
      .main(MainClass.java:29) 
Caused by: com.baeldung.chainedexception.exceptions
  .TeamLeadUpsetException: Team lead Upset.
    at com.baeldung.chainedexception.exceptions.MainClass
  .howIsTeamLead(MainClass.java:44) 
    at com.baeldung.chainedexception.exceptions.MainClass
  .getLeave(MainClass.java:34) 
    ... 1 more

我们可以很容易地比较显示的日志,并得出结论,链式异常会导致更干净的日志。