C# 没有 catch 块的 finally 块是 Java 反模式吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/601152/
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
Is a finally block without a catch block a java anti-pattern?
提问by Jared
I just had a pretty painful troubleshooting experience in troubleshooting some code that looked like this:
我在对一些看起来像这样的代码进行故障排除时遇到了非常痛苦的故障排除经验:
try {
doSomeStuff()
doMore()
} finally {
doSomeOtherStuff()
}
The problem was difficult to troubleshoot because doSomeStuff() threw an exception, which in turn caused doSomeOtherStuff() to also throw an exception. The second exception (thrown by the finally block) was thrown up to my code, but it did not have a handle on the first exception (thrown from doSomeStuff()), which was the real root-cause of the problem.
这个问题很难解决,因为 doSomeStuff() 抛出了一个异常,这反过来又导致 doSomeOtherStuff() 也抛出了一个异常。第二个异常(由 finally 块抛出)被抛出到我的代码中,但它没有处理第一个异常(从 doSomeStuff() 抛出),这是问题的真正根本原因。
If the code had said this instead, the problem would have been readily apparent:
如果代码改为这样,问题就很明显了:
try {
doSomeStuff()
doMore()
} catch (Exception e) {
log.error(e);
} finally {
doSomeOtherStuff()
}
So, my question is this:
所以,我的问题是:
Is a finally block used without any catch block a well-known java anti-pattern? (It certainly seems to be a not-readily-apparent subclass of the obviously well-known anti-pattern "Don't gobble exceptions!")
在没有任何 catch 块的情况下使用 finally 块是众所周知的 Java 反模式吗?(它当然似乎是明显众所周知的反模式“不要吞噬异常!”的一个不太明显的子类)
采纳答案by dsimcha
In general, no, this is not an anti-pattern. The point of finally blocks is to make sure stuff gets cleaned up whether an exception is thrown or not. The whole point of exception handling is that, if you can't deal with it, you let it bubble up to someone who can, through the relatively clean out-of-band signaling exception handling provides. If you need to make sure stuff gets cleaned up if an exception is thrown, but can't properly handle the exception in the current scope, then this is exactly the correct thing to do. You just might want to be a little more careful about making sure your finally block doesn't throw.
一般来说,不,这不是反模式。finally 块的目的是确保无论是否抛出异常,都可以清除内容。异常处理的全部意义在于,如果你不能处理它,你就让它冒泡给可以通过相对干净的带外信号异常处理提供的人。如果您需要确保在抛出异常时清理内容,但无法在当前范围内正确处理异常,那么这正是正确的做法。您可能只想更加小心地确保您的 finally 块不会抛出。
回答by billjamesdev
I'd say a try block without a catch block is an anti-pattern. Saying "Don't have a finally without a catch" is a subset of "Don't have a try without a catch".
我会说没有 catch 块的 try 块是一种反模式。说“不要在没有抓住的情况下进行最终”是“没有抓住就不要尝试”的一个子集。
回答by Bryan Kyle
There is absolutely nothing wrong a try with a finally and no catch. Consider the following:
尝试使用 finally 和 no catch 绝对没有错。考虑以下:
InputStream in = null;
try {
in = new FileInputStream("file.txt");
// Do something that causes an IOException to be thrown
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// Nothing we can do.
}
}
}
If an exception is thrown and this code doesn't know how to deal with it then the exception should bubble up the call stack to the caller. In this case we still want to clean up the stream so I think it makes perfect sense to have a try block without a catch.
如果抛出异常并且此代码不知道如何处理它,则异常应该将调用堆栈向上冒泡给调用者。在这种情况下,我们仍然想清理流,所以我认为有一个没有捕获的 try 块是非常有意义的。
回答by Logan Capaldo
I think the real "anti-pattern" here is doing something in a finallyblock that can throw, not not having a catch.
我认为这里真正的“反模式”是在一个finally可以抛出的块中做一些事情,而不是没有抓住。
回答by Julien Grenier
I use try/finally in the following form :
我以以下形式使用 try/finally :
try{
Connection connection = ConnectionManager.openConnection();
try{
//work with the connection;
}finally{
if(connection != null){
connection.close();
}
}
}catch(ConnectionException connectionException){
//handle connection exception;
}
I prefer this to the try/catch/finally (+ nested try/catch in the finally). I think that it is more concise and I don't duplicate the catch(Exception).
我更喜欢这个而不是 try/catch/finally(在 finally 中嵌套 try/catch)。我认为它更简洁,我不复制catch(Exception)。
回答by TofuBeer
try {
doSomeStuff()
doMore()
} catch (Exception e) {
log.error(e);
} finally {
doSomeOtherStuff()
}
Don't do that either... you just hid more bugs (well not exactly hid them... but made it harder to deal with them. When you catch Exception you are also catching any sort of RuntimeException (like NullPointer and ArrayIndexOutOfBounds).
也不要这样做......你只是隐藏了更多的错误(好吧并没有完全隐藏它们......但是更难处理它们。当你捕获异常时,你也会捕获任何类型的RuntimeException(如NullPointer和ArrayIndexOutOfBounds) .
In general, catch the exceptions you have to catch (checked exceptions) and deal with the others at testing time. RuntimeExceptions are designed to be used for programmer errors - and programmer errors are things that should not happen in a properly debugged program.
通常,捕获您必须捕获的异常(已检查的异常)并在测试时处理其他异常。RuntimeExceptions 旨在用于程序员错误 - 程序员错误是不应该在正确调试的程序中发生的事情。
回答by Jason
I think that try with no catch is anti-pattern. Using try/catch to handle exceptionalconditions (file IO errors, socket timeout, etc) is not an anti-pattern.
我认为没有捕获的尝试是反模式。使用 try/catch 来处理异常情况(文件 IO 错误、套接字超时等)不是一种反模式。
If you're using try/finally for cleanup, consider a using block instead.
如果您使用 try/finally 进行清理,请考虑使用 using 块。
回答by OscarRyz
Not at all.
一点也不。
What's wrong is the code inside the finally.
有什么问题是finally里面的代码。
Remember that finally will always get executed, and is just risky ( as you have just witnessed ) to put something that may throw an exception there.
请记住,finally 总是会被执行,并且在那里放置可能会引发异常的东西是有风险的(正如您刚刚看到的)。
回答by Ravi Wallau
I think it's far from being an anti-pattern and is something I do very frequently when it's critical do deallocate resources obtained during the method execution.
我认为这远不是一种反模式,而是我经常做的事情,当它在方法执行期间释放获得的资源至关重要时。
One thing I do when dealing with file handles (for writing) is flushing the stream before closing it using the IOUtils.closeQuietly method, which doesn't throw exceptions:
我在处理文件句柄(用于写入)时做的一件事是在使用 IOUtils.closeQuietly 方法关闭流之前刷新流,该方法不会引发异常:
OutputStream os = null;
OutputStreamWriter wos = null;
try {
os = new FileOutputStream(...);
wos = new OutputStreamWriter(os);
// Lots of code
wos.flush();
os.flush();
finally {
IOUtils.closeQuietly(wos);
IOUtils.closeQuietly(os);
}
I like doing it that way for the following reasons:
我喜欢这样做,原因如下:
- It's not completely safe to ignore an exception when closing a file - if there are bytes that were not written to the file yet, then the file may not be in the state the caller would expect;
- So, if an exception is raised during the flush() method, it will be propagated to the caller but I still will make sure all the files are closed. The method IOUtils.closeQuietly(...) is less verbose then the corresponding try ... catch ... ignore me block;
- If using multiple output streams the order for the flush() method is important. The streams that were created by passing other streams as constructors should be flushed first. The same thing is valid for the close() method, but the flush() is more clear in my opinion.
- 关闭文件时忽略异常并不是完全安全的 - 如果有尚未写入文件的字节,则文件可能未处于调用者期望的状态;
- 因此,如果在 flush() 方法期间引发异常,它将传播给调用者,但我仍然会确保所有文件都已关闭。方法 IOUtils.closeQuietly(...) 比相应的 try ... catch ... ignore me 块更简洁;
- 如果使用多个输出流,flush() 方法的顺序很重要。通过将其他流作为构造函数传递而创建的流应首先刷新。同样的事情对 close() 方法有效,但我认为 flush() 更清楚。
回答by Tom Hawtin - tackline
In my opinion, it's more the case that finallywith a catchindicate some kind of problem. The resource idiom is very simple:
在我看来,更多的情况finally是catch表明某种问题。资源习语非常简单:
acquire
try {
use
} finally {
release
}
In Java you can have an exception from pretty much anywhere. Often the acquire throws a checked exception, the sensible way to handle that is to put a catch around the how lot. Don't try some hideous null checking.
在 Java 中,您几乎可以在任何地方遇到异常。通常,acquire 会抛出一个已检查的异常,处理这种情况的明智方法是在数量上放置一个捕获。不要尝试一些可怕的空检查。
If you were going to be really anal you should note that there are implied priorities among exceptions. For instance ThreadDeath should clobber all, whether it comes from acquire/use/release. Handling these priorities correctly is unsightly.
如果你真的想成为肛门的,你应该注意到例外之间有隐含的优先级。例如 ThreadDeath 应该破坏所有,无论它来自获取/使用/释放。正确处理这些优先级是不雅观的。
Therefore, abstract your resource handling away with the Execute Around idiom.
因此,请使用 Execute Around 习语将您的资源处理抽象化。

