![](/img/trans.png)
[英]How to handle different exception http types with try-catch in Java?
[英]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
。
如果两个方法调用都可以抛出不是FailedToDoSomethingException
的Exception
,则您必须具有更特定的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.