3

我对异常进行了广泛的研究,但我仍然迷路了。我想知道做什么好或不好。

我还希望您就以下示例给我您的专家意见:

public void myprocess(...) {
    boolean error  = false;

    try {

        // Step 1
        try {
            startProcess();
        } catch (IOException e) {
            log.error("step1", e);
            throw new MyProcessException("Step1", e);
        }

        // Step 2
        try {
            ...
        } catch (IOException e) {
            log.error("step2", e);
            throw new MyProcessException("Step2", e);
        } catch (DataAccessException e) {
            log.error("step2", e);
            throw new MyProcessException("Step2", e);       
        }

        // Step 3
        try {
            ...
        } catch (IOException e) {
            log.error("step3", e);
            throw new MyProcessException("Step3", e);
        } catch (ClassNotFoundException e) {
            log.error("step3", e);
            throw new MyProcessException("Step3", e);       
        }

        // etc.

    } catch (MyProcessException mpe) {
        error = true;       
    } finally {
        finalizeProcess(error);
        if (!error) {
            log.info("OK");
        } else {
            log.info("NOK");
        }           
    }
}
  1. 是否可以在每个步骤中抛出个人异常 (MyProcessException) 以管理全局 try...catch...finally ?
  2. 可以管理每个步骤的每个已知异常吗?

谢谢您的帮助。


编辑 1:

这是一个很好的做法吗?通过获取消息直接登录全局catch,并在上层尝试...catch(Exception)...。

目的是在步骤失败时停止,并最终确定过程(错误与否)。

In Controller

public void callProcess() {
    try {
        myprocess(...);
    } catch (Exception e) {
        log.error("Unknown error", e);
    }   
}

In Service

public void myprocess(...) {
    boolean error  = false;

    try {

        // Step 1
        try {
            startProcess();
            log.info("ok");
        } catch (IOException e) {
            throw new MyProcessException("Step1", e);
        }

        // Step 2
        try {
            ...
        } catch (IOException e) {
            throw new MyProcessException("Step2", e);
        } catch (DataAccessException e) {
            throw new MyProcessException("Step2", e);       
        }

        // Step 3
        try {
            ...
        } catch (IOException e) {
            throw new MyProcessException("Step3", e);
        } catch (ClassNotFoundException e) {
            throw new MyProcessException("Step3", e);       
        }

        // etc.

    } catch (MyProcessException mpe) {
        error = true;       
        log.error(mpe.getMessage(), mpe);           
    } finally {
        finalizeProcess(error);
        if (!error) {
            log.info("OK");
        } else {
            log.info("NOK");
        }           
    }
}

谢谢你。


编辑 2:

在较低级别捕获 (Exception e) 并抛出个人异常是一种真正的坏习惯吗?

4

6 回答 6

2

不存在通用规则,这取决于您的需求。您可以抛出个人异常,并且可以管理每个已知异常。

但请注意,重要的是你想要什么。

try{
   exec1();
   exec2(); // if exec1 fails,  it is not executed
}catch(){}

try{
   exec1();
}catch(){}

try{
   exec2(); // if exec1 fails,  it is  executed
}catch(){}
于 2013-02-06T10:28:48.493 回答
2

在上面的示例中,抛出您自己的自定义异常可能是可以接受的。

想象一下,我有一些数据访问对象 (DAO),它们有不同的风格(SQL、读/写文件等)。我不希望每个 DAO 都抛出特定于其存储机制的异常(与 SQL 相关的异常等)。我希望他们抛出一个CouldNotStoreException,因为这是客户正在处理的抽象级别。抛出与 SQL 相关或与文件相关的异常会暴露内部工作原理,而客户端对此并不特别感兴趣。他们只想知道读/写操作是否有效。

您可以使用原始异常作为原因来创建自定义异常。这样您就不会丢失围绕您的问题的原始信息。

在上面我可能不会像你所做的那样处理每个步骤中的每个异常。如果出现异常后处理无法继续,我只需将整个代码块包装在异常处理块中。它提高了可读性,您不必捕获异常,然后(稍后)检查处理状态以查看是否可以正常进行(如果您不这样做,您将为一个生成许多异常原始问题,这没有帮助)。

我会考虑catch {}每个异常的多个块是否添加任何东西(你是否为每个块做不同的事情?)。请注意,Java 7允许您在一个 catch{} 中处理多个异常类(我意识到您使用的是 Java 6,但为了完整性我注意到这一点)。

最后,也许您想考虑一下已检查与未检查的异常

于 2013-02-06T10:28:16.140 回答
1

异常机制的要点是减少和组合处理代码。您正在以没有例外的语言的典型风格处理它们,例如 C:每次出现都有一个单独的处理块。

在大多数情况下,最好的选择是用一个包罗万象的方法包围整个方法代码:

try {
 .... method code ...
} 
catch (RuntimeException e) { throw e; } 
catch (Exception e) { throw new RuntimeException(e); }

唯一不合适的地方是您要插入特定的处理代码,或者包装在稍后将专门处理的自定义异常中。

大多数异常,尤其是IOExcption在您的情况下,仅代表失败,除了记录它并将应用程序返回到可以处理进一步请求的安全点之外,不会进行任何处理。如果您发现自己一遍又一遍地重复相同的处理代码,这表明您做错了。

一个非常重要的规则:要么处理,要么重新抛出;永远不要两者都做。这就是您在示例中所做的:记录和重新抛出。重新抛出的异常很可能会在调用堆栈中被进一步捕获并再次记录。阅读生成的日志文件是一场噩梦,但不幸的是,这是一场非常熟悉的噩梦。

于 2013-02-06T10:28:45.443 回答
0
int step = 0;

try
{
    step = 1;
    ...
    step = 2;
    ...
    step = 3;
    ...
}
catch (Exception1 e)
{
    log ("Exception1 at step " + step);
    throw new MyException1 ("Step: " + step, e);
}
catch (Exception2 e)
{
    log ("Exception2 at step " + step);
    throw new MyException2 ("Step: " + step, e);
}
...
于 2013-02-06T10:29:52.437 回答
0

我会说这取决于您的需求...

如果 step2 即使 step1 失败也能正确执行,您可以单独 try/catch step1。
否则,我会将所有步骤组合在一个 try/catch 块中,并确保各个步骤在失败时生成日志消息。这样您就不会乱扔代码并且仍然知道出了什么问题

捕获每个已知异常是可以的,因此您可以记录发生了什么异常以及发生的原因。

于 2013-02-06T10:30:44.953 回答
0

这里有一些异常处理模式/反模式的链接:

做:

不:

关于创建您自己的异常,如果您正在创建 API、框架或另一段可重用代码,它当然很有用,但在常规应用程序中,它更具争议性,我个人建议坚持现有的异常。

于 2013-02-06T10:35:38.120 回答