C# - 异常处理 087 天天速看料
异常即程序运行时发生的错误(错误并不总是编程人员的原因,有时应用程序也会因为用户或运行代码的环境改变而发生错误;越大的程序越容易发生异常
异常处理(exceptional handling)机制分离了接收和处理错误代码,功能用于理清编程者的思绪,增强了代码可读性,方便了后期维护者的阅读和理解
(相关资料图)
异常处理(或错误处理)提供了处理程序运行时出现的任何意外或异常情况的方法,异常处理中使用 try,catch与finally三个关键字来尝试处理捕获的异常(不可能捕获所有的异常)
1)发现错误(使用try包裹可能会出现的异常代码,一般叫做异常捕获) 2)处理错误(在catch语句块处理捕获异常) 3)不论异常在2)中是否处理都会执行
注意事项:
1)发生异常后,在try语句块中异常代码之后的代码不再执行
2)finally块中的代码,无论是否发生异常都会执行;也不能写return语句(报错)
3)即使try语句块中有return语句,finally语句块也会执行
4)如果所有的异常都不匹配catch,最后依然执行finally语句块中的代码(如果有)
语法错误类的异常
这个异常绝大多数VS工具会帮我们识别出来,基本无法生成程序集;处理方法:根据错误列表的提示一一改正语法错误的代码
static void Main(string[] args){//应该与行号12 形成闭合的语句块 //1 语法错误 //类型应该是 小写 int Int num = 6; //int i=0后面应该是分号 for (int i = 0,i < 6; i++) { Console.WriteLine(i); } Console.ReadKey(); //}//不小心注释掉导致Main()方法的语句块无法闭合 //这类错误太多无法穷举,VS会有提示
语法错误的异常
处理时先按行号最小,行号相同的按列号进行处理(前面的错误会导致后面出现许多"无效"的关联错误)如上图只因一个分号隐藏了Int,关联了除X1外六个错误信息
逻辑错误错误类的异常
这个异常编译没问题,执行不报异常,就是结果不对;处理方法:可以通过调试监视变量
static void Main(string[] args){ //逻辑错误 //如本来是计算两个数的和 int n = 3; int m = 2; //不小心书将 + 写为 - int sum = n - m;//结果 1 Console.WriteLine("n + m = {0}", sum); //简化的逻辑错误代码示例 //如果出现在复杂的来回调用的方法中... //最好通过调试监视经过每个方法后变量的值 Console.ReadKey();}
以上两种类型的异常基本用不到异常处理机制
导致程序崩溃的异常
可以通过编译,只是在程序运行期间出现错误,导致程序崩溃;这个需要使用异常处理机制,使用它可以使程序跳过这个异常代码,继续执行这个异常之后的代码(已捕获了异常)
现今可以遇到的如:
1)两个操作数相除或取余时的异常;尝试除以零
2)使用如使用Convert,Parse,TryParse等进行类型转换;输入字符串的格式不正确
3)使用引用类型对象时;未将对象引用设置到对象的实例
4)其他的如操作文件或数据库时等因文件没了或没有操作权限等
static void Main(string[] args){ //编译成功,运行抛异常 //1 尝试除以零 int n = 8; int m = 0; int s = n / m; //抛异常 //2 输入字符串的格式不正确 string num = "ooo";//字母o Convert.ToInt32(num); int.Parse("ooo"); int.TryParse(num, out n); //引用类型容易出现的异常 //3 未将对象引用设置到对象的实例 //专有名词: 空指针异常 string str = null; str.ToString(); Console.ReadKey();}
代码抛出异常
程序抛出异常导致程序崩溃,无法继续执行,会给用户带来非常不好的使用体验(什么垃圾破软件....)
捕获异常并处理
异常处理的一般应用模式(三者同用方式):
try{捕获有可能出现异常的代码}当遇到异常时,try语句块中后续代码不再执行。
catch{处理捕获的异常}一般操作如记录日志,向上抛出等操作(只有发生了异常才会执行)
catch语句块中有时使用throw关键字将捕获的异常抛给"上级"去处理
finally{无论是否发生或捕获异常都会执行的代码}一般用于释放内存或资源等操作
其他的应用方式:
方式1) try → 多个catch → 一个finally
方式2) try→(1个或多个catch)多个catch的顺序问题,没有finally。
方式3) try→finally(只能有一个)没有catch
static void Main(string[] args) { Console.WriteLine("1 程序开始执行"); //这个赋值在此没有任何错误 string num = "ooo"; try { //有可能发生异常的代码 int s = 0; Console.WriteLine("2 抛出异常之前 s = {0}", s); //当程序执行到异常代码后会直接跳转到catch语句块中 s = int.Parse(num);//有可能抛出异常 Console.WriteLine("3 抛出异常之后 s = {0}", s); //除了行号11,其余基本都是"无效"代码 //两个输出语句主要是显示有异常时 //在异常代码前后的代码执行情况 } catch (Exception) //Exception处理异常的类 { //只有try中有异常时才会进入此语句块 //如果try中没有异常,直接跳转到finally语句块中 Console.WriteLine("4 程序发生异常了!!!"); //执行完后跳转到finally语句块中 } finally { Console.WriteLine("5 无论前面是否发生异常都会跳转到此语句块中"); } Console.WriteLine("6 程序结束"); Console.ReadKey(); }
抛出异常
遇到异常时,使用此方式的执行过程如上图所示,可通过调试查看整个代码执行顺序
4.1 catch中可以指定异常对象,它有3个重要属性
Source:属性表示导致异常发生的应用程序或对象的名称
Message:提供引起异常的详细信息
StackTrace:此属性提供抛异常的详细信息,并首先显示最近调用的方法
异常对象
static void Main(string[] args){ string str = null; try { //有可能发生异常的代码 Console.WriteLine(str.ToString()); } catch (Exception ex)//ex 异常对象 { //Exception 几乎可以捕获所有的异常(理论上) Console.WriteLine("ex.Source\r\n {0}", ex.Source); Console.WriteLine(""); Console.WriteLine("ex.Message\r\n {0}", ex.Message); Console.WriteLine(""); Console.WriteLine("ex.StackTrace\r\n {0}",ex.StackTrace); //1)写入日志 //2)通过throw 向上抛异常(由有处理权限或者专门的"上级"进行处理) } Console.ReadKey();}
使用其他方式中的方式2可以有针对的对某种类型的异常进行捕获处理
static void Main(string[] args){ string str = null; try { Console.WriteLine(str.ToString()); } //只为演示多catch的用法与原则 //指定捕获处理空指针异常 //如果发生的异常没有被特定的异常类捕获 //等同于没有设置异常捕获 catch (NullReferenceException nullex) { Console.WriteLine("nullex.Message\r\n {0}", nullex.Message); } //指定捕获处理 除数为0的异常 catch (DivideByZeroException divex) { Console.WriteLine("divex.Message\r\n {0}", divex.Message); } //指定捕获处理 输入的字符串不合格的异常 catch (FormatException fex) { Console.WriteLine("divex.Message\r\n {0}", fex.Message); } //可以指定许多的异常类型 //Exception 相当于其他所有异常类的"祖宗"类 //用于在上述几个异常类的最后 //Exception 不要写在第一个,否则后面针对特定异常的类就不起作用了 catch (Exception ex) { //可以将上面没有捕获到的异常捕获到 Console.WriteLine("ex.Message\r\n {0}", ex.Message); } Console.ReadKey();}
自己捕获了异常不想进行处理或没有权限进行处理,可以使用throw将异常抛给"上级"进行处理
static void Main(string[] args){ try { M1(); } catch (Exception ex) { //将M1()中的异常信息传递到了ex中 //显示异常类型的信息 Console.WriteLine(ex.Message); //显示抛异常的具体信息 Console.WriteLine(ex.InnerException.ToString()); } Console.ReadKey();}static void M1(){ string str = null; try { Console.WriteLine(str.ToString()); } //处理空指针异常(假设只可能出现此类异常) catch (NullReferenceException nullex) { //将捕获的异常信息最好先存储在日志中 //将异常抛给"上级" throw new Exception("出异常了,啦!啦啦!!啦啦啦!!!", nullex); }}
向上抛出异常
throw也可以单独使用,人为的制造异常;最近关于#鼠头鸭被禁#的事,舆情哗然,编写一个类似验证感词的程序,只要输入了敏感词就抛出异常
static void Main(string[] args){ Console.WriteLine("请输热点敏感词"); string str = Console.ReadLine(); Console.WriteLine(""); if (str.Trim() == "鼠头鸭") { throw new Exception(" (⊙_⊙) !!!"); } else { Console.WriteLine("热点敏感词 {0}", str); } Console.ReadKey();}
单独使用 throw 抛出异常
建议:最好通过逻辑判断(if-else)等语句以减少异常发生的可能性,节省性能损耗
使用异常捕获机制的益处:不会因为某段功能代码,导致整个程序崩溃(假设是计算器有加减乘除四种功能,除法因为除零抛异常,可暂时使用其他功能)提升用户体验感(类似访问的网站,某个网页已"删除",用户找不到,将页面重定向到指定的网页,不会出现304等不友好的网页)
关键词:
推荐阅读
域名抢注是是什么意思?投资角度来看什么域名好?
域名抢注是是什么意思域名抢注是通过抢先注册的方式获得互联网删除的域名的使用权。域名是由点分隔的一串数字,用于标记一台计算机或一组计 【详细】
捷达保养费用是多少?捷达是哪个国家的品牌?
捷达保养费用是多少?全新捷达的保修期为2年或6万公里,以先到者为准,新车可享受一次免费保养,首次免费保养在5000-7500km或1年内进行。如 【详细】
天然气泄露会造成爆炸吗?天然气泄漏怎么办?
天然气泄露会造成爆炸吗?家里用的天然气如果泄露是会发生爆炸的。当空气中含有混合天然气时,在与火源接触的一系列爆炸危险中,就会发生爆 【详细】
四部门明确App收集个人信息范围 个人信息保护范围判断标准
四部门明确App收集个人信息范围近日,国家互联网信息办公室、工业和信息化部、公安部、国家市场监督管理总局联合印发《常见类型移动互联网 【详细】
丰田致炫介绍 致炫威驰对比汇总
丰田致炫介绍参考价格: 6 88ー10 28W,基本参数: 1 3升 1 5升 5mt,5 3升 100公里。YARiS L致炫是YARiS L的替代传统车型,也是我们中国 【详细】
相关新闻
- C# - 异常处理 087 天天速看料
- 智能手环到底有没有购买必要?-当前最新
- 【当前热闻】已过时的窗机空调,为何还那么多人用,除了便宜,还有这4个优势
- 金融监管加码,一天75张罚单!兴业、广发被罚,招商银行涉房贷款违规频发 环球简讯
- 上错花轿之三嫁奇缘唐艺昕_上错花轿之三嫁奇缘
- 天天观天下!脚太冰是什么原因(脚很冰是什么原因)
- 时讯:由“制”到“智”的升级转型——福建省加快建设先进制造业强省观察
- 今日仙之侠道2玖章攻略视频_仙之侠道2玖章攻略 快看点
- 环球动态:俄媒:普里戈任与瓦格纳集团武装人员已全部从俄南部军区司令部撤离
- 今日热搜:LG手机,现在成了闲鱼上最火的洋垃圾
- 10年63亿美元没了!中国人造太阳获重大突破后,全球最大的或烂尾
- 快消息!618刚结束,阿里紧急换帅,互联网正在进入分水岭
- 此国一架飞机坠毁,6人失踪 世界快看
- 香蕉和什么相克(香蕉不能和哪些东西一起吃)-世界观察
- 全球今亮点!微信系统维护要多久2021_微信系统维护要多久2020
- 迷你世界雨寒辅助最新版2021_迷你世界雨寒辅助怎么下载
- 单调的反义词(傲然的反义词)
- 阿里巴巴开店流程及费用多少钱_阿里巴巴开店流程及费用 天天精选
- 环球观焦点:花店是如何保存鲜花的_花店鲜花如何保鲜简介介绍
- 炖白水肉的做法? 世界聚看点