我理解try-catch如何工作以及try-finally如何工作,但我发现自己在两个完全不同的场景中使用它们(通常):
using在C#和VB中)主要用于某些中型代码块,它使用一些需要正确处理的资源.根据我的经验,try-catch-finally最合适的情况,即我想要捕获某个特定异常的块与我使用某些可处理资源的块完全相同,这种情况极为罕见.然而,C#,VB和Java的语言设计者似乎认为这是一个非常常见的场景; VB的设计师甚至考虑增加捕捉到using.
我错过了什么吗?或者我是否因为限制性地使用try-catch而过于迂腐?
编辑:澄清:我的代码通常看起来像这样(为清晰起见,函数展开):
Try
do something
Aquire Resource (e.g. get DB connection)
Try
do something
Try
do something that can fail
Catch SomeException
handle expected error
do something else...
Finally
Close Resource (e.g. close DB connection)
do something
Catch all
handle unexpected errors
Run Code Online (Sandbox Code Playgroud)
这似乎比将两个捕获中的任何一个放在同一水平上更有意义,最后只是为了避免缩进.
public class FinallyTest {
static int i=0;
public static void main(String a[]){
while(true){
try{
i=i+1;
return;
}finally{
i=i+1;
break;
}
}
System.out.println(i);
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码输出是'2'.我所期待的是什么都不应该打印出来.究竟什么'打破'在这做什么?请解释.谢谢
似乎finally块不执行,如果它不是主线程执行代码.在这种情况下是否有可能强制执行?
环境:VS 2010,.Net Framework 4.0.3
class Program
{
static void Main(string[] args)
{
var h = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(
obj => TestProc(h));
h.WaitOne();
}
private static void TestProc(EventWaitHandle h)
{
try
{
Trace.WriteLine("Try");
h.Set();
}
catch(Exception)
{
Trace.WriteLine("Catch");
}
finally
{
Thread.Sleep(2000);
Trace.WriteLine("Finally");
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
我在MSDN中找到了关于该案例的提及和解释:
ThreadAbortException类 http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx
当调用Abort方法来销毁线程时,公共语言运行库会抛出ThreadAbortException.ThreadAbortException是一个可以捕获的特殊异常,但它会在catch块的末尾自动再次引发.引发此异常时,运行时会在结束线程之前执行所有finally块.因为线程可以在finally块中执行无限制计算或调用Thread.ResetAbort来取消中止,所以无法保证线程将永远结束.如果要等到中止的线程结束,可以调用Thread.Join方法.Join是一个阻塞调用,在线程实际停止执行之前不会返回.
注意:
当公共语言运行库(CLR)在托管可执行文件中的所有前台线程结束后停止后台线程时,它不使用Thread.Abort.因此,您无法使用ThreadAbortException来检测CLR何时终止后台线程.
前景和背景线程 http://msdn.microsoft.com/en-us/library/h339syd0.aspx
当运行时停止后台线程因为进程正在关闭时,线程中不会抛出异常.但是,当因为AppDomain.Unload方法卸载应用程序域而停止线程时,前台和后台线程中都会抛出ThreadAbortException.
那么为什么在应用程序结束时CLR不会使用AppDomain.Unload方法在主进程结束(kill)之前卸载应用程序域?因为http://msdn.microsoft.com/en-us/library/system.appdomain.unload.aspx:
当线程调用Unload时,目标域将标记为卸载.专用线程尝试卸载域,并且域中的所有线程都将中止.如果线程没有中止,例如因为它正在执行非托管代码,或者因为它正在执行finally块,那么在一段时间之后,在最初调用Unload的线程中抛出CannotUnloadAppDomainException.如果最终无法中止的线程结束,则不会卸载目标域.因此,在.NET Framework 2.0版域中不保证卸载,因为它可能无法终止执行线程.
结论:在某些情况下,我需要考虑我的代码是否会在后台或前台线程中执行?在应用程序主线程结束所有工作之前,我的代码是否可能无法完成?
我很困惑为什么我需要将清理代码放在一个finally块中关闭流.
我已经读过finally块中的代码无论如何都会运行(是否存在异常); 并且在finally块运行之后,该方法的其余部分继续.
我的问题是:如果方法的其余部分必须继续,那么为什么我不在函数中的try/catch块之后放入清理代码?
当使用Invoke-Sqlcmd连接到SQL Server失败时,我在PowerShell中捕获错误时遇到问题.这是一些用于演示此问题的通用代码:
CLS
$server = "Localhost\fake"
try
{
Invoke-Sqlcmd -Query "SELECT DB_NAME() as [Database]" -Server $server
}
catch
{
Write-Host "Error connecting to server " $server
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
Invoke-Sqlcmd:建立与SQL Server的连接时发生与网络相关或特定于实例的错误.服务器未找到或无法访问.验证实例名称是否正确,以及SQL Server是否配置为允许远程连接.(提供者:命名管道提供程序,错误:40 - 无法打开与SQL Server的连接)
我期待获得一行声明:"连接到服务器Localhost\fake时出错"
正如Eric Lippert在本文中所描述的那样,yield return不允许在try/catch条款内.
有没有一种很好的方式我可以得到这样的东西,而不必IEnumerator手工编写我自己的东西:
public IEnumerable<Data> GetData()
{
var transaction = Session.BeginTransaction());
try
{
IQuery q = CreateQuery(session);
foreach (var result in q.Enumerable())
yield return ProjectResult(result); // <-- doesn't work
session.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw;
}
finally
{
transaction.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud) 在查看我的代码覆盖率时,我注意到很多单元测试无法检查最终块,这些块试图关闭finally块中的打开InputStreams.
一个示例摘录是:
try {
f = new BufferedInputStream(new FileInputStream(source));
f.read(buffer);
} finally {
if (f != null)
try {
f.close();
} catch (IOException ignored) {
}
}
}
Run Code Online (Sandbox Code Playgroud)
有没有适当的解决方案来使用JUnit4检查finally块内的所有内容?
我知道在保持最高生产力的同时,无法实现100%的代码覆盖率.然而,这些红线在报告中引人注目.
有没有办法访问在finally块中的try/catch块中创建的val?或者是最终块超出范围.
def myTryCatch: Either[Exception, String] = {
try {
val w = runOrFailWithException("Please work...")
Right(w)
} catch {
case ex: Exception => {
Left(ex)
}
}
finally {
// How do I get access to Left or Right in my finally block.
// This does not work
_ match {
case Right(_) =>
case Left(_) =>
}
}
}
Run Code Online (Sandbox Code Playgroud) 我有以下代码
public static void nocatch()
{
try
{
throw new Exception();
}
finally
{
}
}
Run Code Online (Sandbox Code Playgroud)
这给出了错误
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Unhandled exception type CustomException
Run Code Online (Sandbox Code Playgroud)
这是预期的,但return在finally块中添加语句会使错误消失
public static void nocatch()
{
try
{
throw new Exception();
}
finally
{
return; //makes the error go away!
}
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下发生了什么事吗?为什么错误会消失?
注意:我编写此代码纯粹是为了实验目的!
java exception-handling exception try-catch try-catch-finally
这只是Go代码的一个简短示例:
package main
import "fmt"
func main() {
defer fmt.Println("world") //use of keyword 'defer'
fmt.Println("hello")
}
Run Code Online (Sandbox Code Playgroud)
我在Java中找到了相当于'defer'的东西.
我可以使用而不是'推迟'
try {
//do something
} finally {
//code using defer
}
Run Code Online (Sandbox Code Playgroud)
没有使用try/catch/finally有没有其他选择?
java ×6
c# ×3
try-catch ×2
.net ×1
break ×1
exception ×1
go ×1
idisposable ×1
java-6 ×1
junit4 ×1
powershell ×1
scala ×1
transactions ×1
vb.net ×1
yield-return ×1