try、catch、finally详解,你不知道的异常处理
介绍
不管是新手还是工作几年的老油条,对try{}catch{}来说是不陌生的。他可以来帮助我们获取异常信息,在try中的代码出现错误,火灾catch代码块中被捕获到。官方也给了详细的解释:。
抛出异常时,公共语言运行库(CLR)会查找catch
处理此异常的语句。如果当前正在执行的方法不包含这样的catch
块,则CLR会查看调用当前方法的方法,依此类推调用堆栈。如果未catch
找到任何块,则CLR向用户显示未处理的异常消息并停止执行该程序。
以上的这些基础我们可能都了解。但是你真的了解他的运行步骤吗?我就是带着这个疑问进行了一下的几个测试。
简单示例:
既然有了疑问就带着疑问想办法验证吧,下面我们通过多个例子来一步一步的分析得到我们想要的结果。
简单的try catch
首先是一个try中没有异常的示例:
static void Main(string[] args)
{
string result =GetStr();
Console.WriteLine(result);
Console.ReadLine();
}
public static string GetStr()
{
try
{
Console.WriteLine("走到:try");
return "这里是try返回值";
}
catch (Exception e)
{
Console.WriteLine("走到:catch");
return "这里是catch返回值";
}
finally
{
Console.WriteLine("走到:finally");
}
return "这里是方法底部返回值";
}
运行结果:
执行分析:
这是最简单最常见的示例,没有发生异常,然后没有走catch,执行顺序是try=>finally=>return;
所有我们得到一个还不确定的结果在GetStr方法中不会执行方法自己的return;
但是finally方法块都会执行;
来个异常的:
下面我们让try方法块出错就好了,然后我们修改一下代码如下:
public static string GetStr()
{
try
{
int value = ;
Console.WriteLine("走到:try");
var i = / value;//这里会出错 0不能被整除
return "这里是try返回值";
}
catch (Exception e)
{
Console.WriteLine("走到:catch");
return "这里是catch返回值";
}
finally
{
Console.WriteLine("走到:finally");
}
return "这里是方法底部返回值";
}
运行结果:
执行分析:
这里在try发生了异常,然后没有正常返回,进入到了catch方法块:try=>catch=>finally=>return;
这里我们可以确定:
- 不管try有没有出错finally方法块都会被执行。【快记笔记,知识点。】
- 就算try和catch方法都有return,finally都会执行;
- 只要try或者catch return返回,try catch 之外的return都无效;
说到这里有些不懂得人可能会有疑问?那在finally写个return是什么结果哪?很不幸的告诉你,不能这么写,写了会怎么样,哼会提示:控制不能离开finally子句主体;
验证return的值
上面我们知道了怎样都会执行finally,但是执行了finally对我们的正返回值有没有印象哪,例如我在try里面对一个变量赋值为a字符串,进行了返回,但是在finally里面修改成了b字符串。会不会被修改哪?
我们还是老代码,然后修改成我们想的样子:
public static string GetStr()
{
string str = "";
try
{
str = "修改成了a";
Console.WriteLine("走到:try");
// return "这里是try返回值";
return str;
}
catch (Exception e)
{
Console.WriteLine("走到:catch");
return "这里是catch返回值";
}
finally
{
str = "修改成了b";
Console.WriteLine("走到:finally");
}
return "这里是方法底部返回值";
}
运行结果:
执行分析:
没有异常还是老样子:执行顺序是try=>finally=>return;
但是我们在finally修改了str字符串,但是通过输出结果我们得到的还是a字符串,
所有我们得到结论:虽然finally方法会被执行但是,返回结果不会被改变,也就是如果finally是在return之后执行的那么他会把返回结果先保存起来,然后不管finally代码执行了什么,都不会影响到返回结果,等finally执行完成在返回结果。
多个重复try
那么我们可以写多个try{}try{}这样的语句吗?不行,会直接报错,其实这样写没有任何意义。
多个重复catch
那么重复多个catch哪?这个是可以的例如下面我这样:
try
{
str = "修改成了a";
Console.WriteLine("走到:try");
// return "这里是try返回值";
return str;
}
catch(InvalidCastException e) {
}
catch (Exception e)
{
Console.WriteLine("走到:catch");
return "这里是catch返回值";
}
这个是被允许的,因为这是有意义的写法。
开始升级
为什么要一定写try-catch-finally 我只写其中一部分不可以吗?
try-catch
那么我们这次不写finally试一试吧。try方法块没有异常已经不用测了,因为上面我们已经确认过了。会返回try的内容。那么就try异常吧。
public static string GetStr()
{
try
{
Console.WriteLine("走到:try");
int value = ;
int s = / value;
return "这里是try返回值";
}
catch (Exception e)
{
Console.WriteLine("走到:catch");
return "这里是catch返回值";
}
return "这里是方法底部返回值";
}
运行结果:
执行分析:
通过可以正常运行我们知道这样写一点问题都没有,所以结果就是
- finally也不是必须的。
- 如果catch没有return 就会返回底部return方法。这是我们的常识。
这样做有什么作用或者意义哪,通常我们可以上面说的定义多个catch来检测异常,还有一个用途就是忽略异常,就是这种异常你系统可以被运行,就可以catch内不写return正常跳过异常执行下面的方法体。但是不是很被建议,
try-finally
那么try-finally哪,这样写也是被允许的。
这样单独写第一就是在finally语句块内做try的资源释放。正常情况下try没有异常,在finally中处理try语句块的资源释放。
第二就是try发生了异常,其实finally起到的作用还是一样的。但是这里区别在于如果异常未经处理,可能就导致程序退出了。所有执不执行已经无所谓了。我们来个异常示例:
static void Main(string[] args)
{
string result = "";
try
{
result = GetStr();
}
catch (Exception e)
{
Console.WriteLine("主方法catch:");
}
Console.WriteLine(result);
Console.ReadLine();
}
public static string GetStr()
{
try
{
Console.WriteLine("走到:try");
int value = ;
int s = / value;
return "这里是try返回值";
} finally
{
Console.WriteLine("走到:finally");
} return "这里是方法底部返回值";
}
运行结果:
执行分析:
try发生了异常,但是因为finally始终都会执行所有也会执行,然后异常被调用方法内的catch捕获执行顺序:try=>finally=>catch(主方法)
所有我们得到结果:
- try-finally可以运行
- try如果没有catch但是发生异常会向上找catch方法块来捕获。知道没有系统崩溃。
以上的例子都是非控制(系统出现异常就自动抛出了)的抛出异常,那么我们可以控制异常的抛出点吗?当然可以。
throw
还是老习惯先上官方解释,发出程序执行期间出现异常的信号。
到底什么意思哪,我个人理解就是一个告诉你是不是出现异常的标志,就像信号灯一样,亮了什么颜色就代表着什么意思 ,当然就是打个比方。信号灯一定是对的,但是这个可不是啊。
简单来总结他就两个功能:第一是告诉别人有异常,第二就是重新发出异常。
告诉别人有异常
简单来说就是自己可以定义一个异常,然后给上层代码处理。(我就是在这想告诉你有异常)
static void Main(string[] args)
{
string result = "";
try
{
Console.WriteLine("主方法try:");
result = GetStr();
}
catch (IndexOutOfRangeException e)
{
Console.WriteLine($"主方法catch抛出异常:{e.GetType().Name}");
}
Console.WriteLine("主方法结束");
Console.ReadLine();
}
public static string GetStr(int index)
{
if (index < || index > )
{
Console.WriteLine("进入异常:");
throw new IndexOutOfRangeException();
}
return "正确返回";
}
运行结果:
执行分析:
在主方法里调用GetStr方法,然后传入了6判断进入if然后给自己给出了异常,退出当前程序进入主方法捕获异常catch中,捕获到异常打印。这里就展示了自己在某种情况下定义一个异常然后给上层抛出。
重新引发异常
这个与上面有什么不同哪,功能都是一样的,但是效果却不一样,这个是我发生了异常但是我不处理,我在继续告诉别人让别人处理。下面我们只需要把上面的GetStr方法修改成这样:
public static string GetStr(int index)
{
try
{
if (index < || index > )
{
Console.WriteLine("进入异常:");
throw new IndexOutOfRangeException();
}
}
catch (Exception e)
{
Console.WriteLine($"进入异常catch重新抛出异常:{e.GetType().Name}");
throw;
}
return "正确返回";
}
运行结果:
执行分析:
在主方法里调用GetStr方法,然后传入了6判断进入if然后给自己给出了异常,在GetStr方法内的catch捕获到异常,但是他没有处理,有重新使用Throw来引发异常,把异常传到了上层(主方法),最后还是主方法的catch来处理异常。
性能的影响
try{ }部分和不加try/catch语句块的效率几乎一样, catch{}部分似乎需要100倍以上的时间 ,所以只要不把try{}catch{}作为你的程序的逻辑,这种设计就是合理的。
try、catch、finally详解,你不知道的异常处理的更多相关文章
- Reactor详解之:异常处理
目录 简介 Reactor的异常一般处理方法 各种异常处理方式详解 Static Fallback Value Fallback Method Dynamic Fallback Value Catch ...
- 详解C#异常处理
一.程序运行时产生的错误通过使用一种称为异常(Exception)的机制在程序中传递,通过异常处理(Exception Handling)有助于处理程序运行过程中发生的意外或异常情况:异常可由CLR和 ...
- JS里try...catch...finally详解,以及console日志调试(console.log、console.info等)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- 【WebApi系列】详解WebApi如何传递参数
WebApi系列文章 [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi参数的传递 [04]详解WebApi测试和PostMan [05]浅谈W ...
- SpringMVC异常处理机制详解[附带源码分析]
目录 前言 重要接口和类介绍 HandlerExceptionResolver接口 AbstractHandlerExceptionResolver抽象类 AbstractHandlerMethodE ...
- 【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析
这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try { //需要被检测的异常代码 } catch(Exception e) { //异常处 ...
- 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)
在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...
- 异常处理与MiniDump详解(2) 智能指针与C++异常
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 一. 综述 <异常处理与MiniDump详解(1) C++异常>稍 ...
- 异常处理与MiniDump详解(1) C++异常(转)
异常处理与MiniDump详解(1) C++异常 write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 一. 综述 我很少敢为自己写 ...
- PHP异常处理详解
PHP异常处理详解 异常处理(又称为错误处理)功能提供了处理程序运行时出现的错误或异常情况的方法. 异常处理通常是防止未知错误产生所采取的处理措施.异常处理的好处是你不用再绞尽脑汁去考虑各种错误, ...
随机推荐
- 加盟阿里!贾扬清被曝从Facebook离职,任阿里硅谷研究院VP
3 月 2 日傍晚,知乎上爆出一则 AI 人事变动大消息——Caffe 作者贾扬清将从 Facebook 离职. 短短数小时,就有近 10 万人浏览这个问题.不仅如此,据 AI 前线爆料,贾扬清离开 ...
- docker-compose搭建mongoDB副本集(1主+1副+1仲裁)
一.基本概念 1.副本集:一个副本集就是一组MongoDB实例组成的集群,由一个主(Primary)服务器和多个备份(Secondary)服务器构成 2.主节点(master):主节点接收所有写入操作 ...
- python基本数据类型之字符串(二)
python基本数据类型之字符串(二) 替换方法 python中字符串的替换方法主要有:center.rjust\ljust.expandtabs.format\format_map(格式化).str ...
- 从开启GTID功能的库同步数据到未开启GTID功能库时,注意事项!
从开启GTID的库中导出数据到未开启GTID的库中,需要注意,在导出的文件中去掉相应的gtid内容,否则导入时会报错如下: ERROR 1839 (HY000) at line 24 in file: ...
- Ubuntu 14.04 LTS 下使用校园网客户端DrclientLinux
原先博客放弃使用,几篇文章搬运过来 下载客户端并解压 安装开发包 sudo -i dpkg --add-architecture i386 #添加32位的支持 apt-get update apt-g ...
- python闭包和延迟绑定
一.什么是闭包: 1.函数内定义函数. 2.外函数的返回时内函数的引用. 3.内函数使用外函数的局部变量(至少一个). 1 def outfunc(): 2 for num in range(4): ...
- 2019swpuj2ee作业2--HTTP协议
简介: HTTP协议:超文本传输协议.它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器.在七层模型中属于应用层.是一种请求/响应式的协议. 主要特点: (1)支持客户端/服 ...
- 前端之html表单
html表单 用于搜集不同类型的用户输入 表单由不同类型的标签组成 1.<form>标签 定义整体的表单区域 * action属性 定义表单数据提交地址 * metho ...
- 《python语言程序设计》_第一章编程题
题目1.1 :显示"welcome to python " 答案:print('welcome to python') 题目1.2:显示"welcome to pytho ...
- 【leetcode】 算法题2 两数相加
问题 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例 ...