繁体   English   中英

如何处理在try-catch中引发普通异常的方法

[英]How to handle method that throws plain Exception in try-catch

考虑以下情况:我有一个对象池,我(1)从中借用一个对象,(2)使用该对象做某事,然后(3)必须将其返回到池中。 挑战在于,前两个步骤可能会引发检查的异常,而步骤(1)甚至会引发普通的Exception

让我向您展示我当前正在使用的代码:

MyObject objectFromPool = null;
try {
    objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
    objectFromPool.doSomething();         // step (2), throws FailedToDoSomethingException
} catch (FailedToDoSomethingException e) {
    throw new MyCustomRuntimeException(e);    
} catch (Exception e) {
    // Now what? Did objectFromPool.doSomething() throw this exception or pool.borrowObject()?
} finally {
    if (objectFromPool != null) {
        pool.returnObject(objectFromPool); // step (3)
    }
}

有什么建议如何处理普通的Exception吗? 我不希望这段代码抛出一个已检查的异常,因为调用者无论如何都不知道如何处理它。 但是我仍然想区分pool.borrowObject()objectFromPool.doSomething()异常,因为前者表示“技术”异常,而后者则表示“业务”问题。

注:我没有控制的代码pool.borrowObject()也不objectFromPool.doSomething() 两者都来自外部库,我不知道它们可能抛出哪种RuntimeException

如果您想知道哪个方法调用引发了异常,请为每个方法引发不同的异常。

根据您的评论,似乎doSomething仅抛出FailedToDoSomethingException 如果是这样,到达第二个catch块( catch (Exception e) )的唯一方法是pool.borrowObject()抛出Exception

如果两个方法调用都可以抛出不是FailedToDoSomethingExceptionException ,则您必须具有更特定的catch块,才能以不同方式处理不同方法抛出的异常。 如果要抛出基本Exception类的实例,则应考虑抛出一个更特定的自定义异常类实例。

我认为更好的方法是将可疑Exception封装为一个特定的异常,该异常最终将落入最终的catch中:

    MyObject objectFromPool = null;
    try {
        try {
                objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
            } catch (Exception e) {
                // Encapsulate into an specific exception type:
                throw new MyOwnException(e);
            }
            objectFromPool.doSomething();         // step (2), throws FailedToDoSomethingException
        } catch (FailedToDoSomethingException e) {
            throw new MyCustomRuntimeException(e);    
        } catch (MyOwnException e) {
            ...
        } finally {
            if (objectFromPool != null) {
                pool.returnObject(objectFromPool); // step (3)
            }
        }

这样,您可以保留原始的catch并最终保留算法,而不必怀疑每个异常的来源。

还有一件事:请记住,异常甚至可能是RuntimeException。 您是否也有兴趣捕获RuntimeExceptions? 如果不是,请添加一个额外的捕获以使它们传播:

        try {
                objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
            } catch (RuntimeException e) {
                // Let it propagate:
                throw e;
            } catch (Exception e) {
                // Encapsulate into an specific exception type:
                throw new MyOwnException(e);
            }

如果两个方法都可能引发普通Exception ,则可以通过将第二个方法包装到新的try / catch块中来区分它们:

try {
    objectFromPool = pool.borrowObject(); 
    try {
        objectFromPool.doSomething();
    } catch (Exception ex){
        // do something
    }  
} catch (Exception e) {
    // pool.borrowObject() throw this e
} finally ...

但是,如果objectFromPool.doSomething()只能抛出FailedToDoSomethingException遵循Eran的回答

怎么样:

MyObject objectFromPool = null;
try{
    try {
        objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
    } catch (Exception e) {
        // pool.borrowObject has thrown exception
    }
    try {
        objectFromPool.doSomething();         // step (2), throws FailedToDoSomethingException
    } catch (FailedToDoSomethingException e) {
        throw new MyCustomRuntimeException(e);    
    }  

} finally {
return pool.returnObject(objectFromPool); // step (3)
}

(按照您提到的进行编辑,您希望始终执行pool.returnObject(objectFromPool);

另一种方法是为每个单独的try-catch块创建一个finally块,而不是此总体try-finally块。

您不能更改所调用方法的代码,并且它们都可以引发简单的Exception 好消息是,您可以通过stacktrace区分哪个方法引发了异常:

MyObject objectFromPool = null;
try {
  objectFromPool = pool.borrowObject();
  objectFromPool.doSomething();
} catch (FailedToDoSomethingException e) {
  throw new MyCustomRuntimeException(e);    
} catch (Exception e) {
  //here we get the method name from the first element in the stack trace
  //this way we can identify the method that actually threw our exception
  if(e.getStackTrace()[0].getMethodName().equals("borrowObject")) {
    //pool.borrowObject threw the exception
  } else if (e.getStackTrace()[0].getMethodName().equals("doSomething")) {
    //objectFromPool.doSomething() threw the exception
  }
} finally {
  if (objectFromPool != null) {
    pool.returnObject(objectFromPool);
  }
}

您甚至可以通过比较stacktrace中的getClassName()来扩展它。

请记住,在重构的情况下这可能容易出错。 如果更改这些方法之一的名称,则if子句可能会失败,以防万一您忘记在此处更改名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM