java 在 catch/finally 块中抛出的吞咽异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1654487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swallowing exception thrown in catch/finally block
提问by maxyfc
Usually I come across situations where I have to swallow an exception thrown by the clean up code in the catch/finallyblock to prevent the original exception being swallowed.
通常我会遇到这样的情况,我必须吞下catch/finally块中的清理代码抛出的异常,以防止原始异常被吞掉。
For example:
例如:
// Closing a file in Java
public void example1() throws IOException {
boolean exceptionThrown = false;
FileWriter out = new FileWriter(“test.txt”);
try {
out.write(“example”);
} catch (IOException ex) {
exceptionThrown = true;
throw ex;
} finally {
try {
out.close();
} catch (IOException ex) {
if (!exceptionThrown) throw ex;
// Else, swallow the exception thrown by the close() method
// to prevent the original being swallowed.
}
}
}
// Rolling back a transaction in .Net
public void example2() {
using (SqlConnection connection = new SqlConnection(this.connectionString)) {
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction = command.BeginTransaction();
try {
// Execute some database statements.
transaction.Commit();
} catch {
try {
transaction.Rollback();
} catch {
// Swallow the exception thrown by the Rollback() method
// to prevent the original being swallowed.
}
throw;
}
}
}
Let's assumed that logging any of the exceptions is not an option in the scope of method block, but will be done by the code calling the example1()and example2()methods.
让我们假设记录任何异常不是方法块范围内的选项,而是由调用example1()和example2()方法的代码完成。
Is swallowing the exceptions thrown by close()and Rollback()methods a good idea? If not, what is a better way of handling the above situations so that the exceptions are not swallowed?
吞下close()和Rollback()方法抛出的异常是个好主意吗?如果不是,那么处理上述情况的更好方法是什么,以便不吞下异常?
回答by duffymo
I'm not a fan of catching and rethrowing an exception.
我不喜欢捕获和重新抛出异常。
If you catch it, do somethingwith it - even if it's just logging the exception.
如果你抓住了它,就用它做点什么——即使它只是记录了异常。
If you can't do anything with it, don't catch it - add a throws clause to the method signature.
如果你不能用它做任何事情,不要抓住它 - 在方法签名中添加一个 throws 子句。
Catching an exception tells me that either you can deal with an exceptional situation and have a recovery plan or "the buck stops here" because an exception cannot propagate in that form any farther (e.g., no stack traces back to the user).
捕获异常告诉我,您可以处理异常情况并制定恢复计划,或者“责任到此为止”,因为异常不能以这种形式传播得更远(例如,没有堆栈跟踪回用户)。
回答by CMerat
You can create a custom Exceptiontype that can hold both exceptions. If you overload the ToString(), you can log both exceptions.
您可以创建一个Exception可以容纳这两种例外情况的自定义类型。如果重载ToString(),则可以记录这两个异常。
try
{
transaction.Commit();
}
catch(Exception initialException)
{
try
{
transaction.Rollback();
}
catch(Exception rollbackException)
{
throw new RollbackException(initialException, rollbackException);
}
throw;
}
回答by fvu
That's exactly why Commons IO has an IOUtils.closeQuietlymethod. In most cases what goes wrong during the closing of a file is not that interesting.
这正是 Commons IO 拥有IOUtils.closeQuietly方法的原因。在大多数情况下,关闭文件期间出现的问题并不那么有趣。
Database transactions that have to be rolled back are potentially more interesting, as in that case the function didn't do what it was supposed to do (put stuff in the DB).
必须回滚的数据库事务可能更有趣,因为在这种情况下,函数没有做它应该做的事情(把东西放在数据库中)。
回答by homeInAStar
There's no reason to rollback the transaction in the C# code. If you close the connection wihtout rolling back the transaction (or committing it) that is equivalent and more efficient...
没有理由在 C# 代码中回滚事务。如果您在不回滚(或提交)事务的情况下关闭连接,则等效且更高效...
public void example2() {
using (SqlConnection connection = new SqlConnection(this.connectionString))
using (SqlCommand command = connection.CreateCommand())
using (SqlTransaction transaction = command.BeginTransaction()) {
// Execute some database statements.
transaction.Commit();
}
}
and you are done.
你就完成了。
The using statement will ensure (via finally) that the connection is closed regardless of any exceptions and let the raw exception bubble out (with the full/correct stack trace). If an exception occurs before the call to Commit, the transaction will never commit and will be automatically rolled back when the transaction/connection closes.
using 语句将确保(通过 finally)无论有任何异常都关闭连接并让原始异常冒泡(带有完整/正确的堆栈跟踪)。如果在调用 Commit 之前发生异常,则事务将永远不会提交,并且会在事务/连接关闭时自动回滚。
回答by Stephen C
I would consider rewriting example1 as follows:
我会考虑如下重写 example1:
// Closing a file in Java
public void example1() throws IOException {
boolean success = false;
FileWriter out = new FileWriter(“test.txt”);
try {
out.write(“example”);
success = true;
out.close();
} finally {
if (!success) {
try {
out.close();
} catch (IOException ex) {
// log and swallow.
}
}
}
}
Moving the success = true;to after the out.close();statement would make the meaning of successa bit clearer ... though it may result in out.close()being called twice.
将success = true;to移到out.close();语句之后会使含义success更清楚一些……尽管它可能会导致out.close()被调用两次。
回答by Mike Chess
Without knowing all of what your particular circumstance is, you could look into throwing a new exception. In C#, at least, when throwing a new exception you one of the optional constructors accepts an existing exception as a parameter. For example:
在不了解您的所有特定情况的情况下,您可以考虑抛出一个新的异常。至少在 C# 中,当抛出新异常时,可选构造函数之一接受现有异常作为参数。例如:
throw new Exception("This is my new exception.", ex);
The purpose of this is to retain the original exception.
这样做的目的是保留原始异常。
Another option might be the try .. catch .. finally construct.
另一种选择可能是 try .. catch .. finally 构造。
try { // normal code that might throw an exception } catch (Exception ex) { // handle that first exception } finally { // handle any cleanup regardless of exception being thrown }
try { // 可能抛出异常的普通代码 } catch (Exception ex) { // 处理第一个异常 } finally { // 处理任何清理,不管抛出的异常如何 }
In general if my code can handle an exception in a particular try .. catch then I don't re-throw that exception. If it is important for something further up the call stack to have that exception I will throw a new exception and set the original exception as the inner exception.
一般来说,如果我的代码可以处理特定 try .. catch 中的异常,那么我不会重新抛出该异常。如果调用堆栈上的某些内容具有该异常很重要,我将抛出一个新异常并将原始异常设置为内部异常。
回答by Steve N
I believe that an exception should be something you don't expect. If you expect an exception then you should do something with it. So in your first example I think you should probably not bother catching the IOException if you are also stating that your method is going to throw IOException.
我相信异常应该是你意想不到的。如果您期望异常,那么您应该对它做些什么。因此,在您的第一个示例中,如果您还声明您的方法将抛出 IOException,我认为您可能不应该费心去捕获 IOException。
回答by evilReiko
usually, risky codes are put allin one try-catch block. nested try-catch blocks are not a very good idea, IMO (or just try to avoid nested try-catch blocks as much as possible, unless you really need them).
通常情况下,风险码把所有在一个try-catch块。嵌套的 try-catch 块不是一个很好的主意,IMO(或者只是尽量避免嵌套的 try-catch 块,除非您真的需要它们)。
because the risky codes are exceptional scenario, so putting exceptional codes for exceptional case for even more exceptional case, that's alot of unnecessary work.
因为有风险的代码是特殊情况,所以把特殊情况的特殊代码放在更特殊的情况下,这是很多不必要的工作。
for example in example1(), place all risky codes in one try-catch block:
例如example1(),将所有有风险的代码放在一个 try-catch 块中:
try{
FileWriter out = new FileWriter(“test.txt”);
out.write(“example”);
out.close();
} catch(Exception e) {
//handle exception
}
OR, another good idea is to place several catch(s) for the same try:
或者,另一个好主意是为同一次尝试放置多个捕获:
try{
FileWriter out = new FileWriter(“test.txt”);
out.write(“example”);
out.close();
} catch(FileNotFoundException e) {
//if IOException, do this..
} catch(IOException e) {
//if FileNotFound, do this..
} catch(Exception e) {
//completely general exception, do this..
}

