Udacity调试课笔记之断言异常
Udacity调试课笔记之断言异常
这一单元的内容不是很多,如Zeller教授所说,就是如何写、检查断言,并如何使用工具实现自动推导出断言的条件。
现在,多数的编程语言,尤其是高级编程语言都会有内置的断言语句或断言函数。而随手编写个简易的断言也不件难事。使用内置的断言会有很多优点,比如获知出错断言的位置,可以通过编程语言的编译参数等来打开或关闭断言——即所谓的优化。
个人觉得,本单元的笔记想写成一篇博文会比较空。算起来,上一单元教授了一个方法、过程,可以让人去遵循、实践。这一单元教的断言,想得简单一点,就只是一条声明语句或函数,仅仅是语法,而且只是一条语法,那有什么可说的;从复杂角度来看,如何准确把握断言条件的选择,这又要靠个人经验的积累,也不是一门甚至一个单元的课程能讲清楚的。所以本单元会比较空洞。
言归正传,Zeller教授把断言分为两种,在测试代码中的断言可以检测某一次运行的结果;而在源代码中的断言则可以在每次运行时进行检测——所以Zeller教授强烈建议在代码,哪怕是产品代码中,都要保留断言。
断言的作用想来认识它的人心里也都清楚,不就是判断异常状态吗?Zeller教授将其细分成三点:
1、捉虫,尽早地发现错误。
2、点有什么区别。
3、文档,断言的条件、它的执行情况都可以作为文档。尤其是根据断言设置的条件,不仅是检查测试的结果,同时还可以生成测试——的用例。
而为了更好地实现断言的目标,可以给每个公共函数设置前置条件断言和后置条件断言。在函数的一开始,用前置条件检查参数性质;在函数结束之前,用后置条件检查结果。
只要函数的大小合理(一个函数1000行就什么都不用说了),那么这些公共函数的前置条件、后置条件综合起来,就会织成一张很大的网,网住程序的大部分状态,减少bug的藏身之处。如果在运行时,断言被触发,那将会离实际的bug更近,从缺陷代码到断言异常之间的程序状态就更少,就更好调试;如果断言最终一个都没被触发,也能因为断言保证了程序一些部分的正确性,而减少调试的工作量。
对于单个函数而言,前置、后置条件断言相当有用。而从整个程序的角度来看,断言也有用武之地。
程序中,有一些数据对象可能会若干个要保持一致的性质。比如像数据结构——树,就一定要无环,所以在增删结点操作之前、之后都需要检查这一性质,正如前置条件断言对参数性质的检查一样。这种始终保持一致的性质就叫数据不变量。
由于数据不变量主要用于大型、复杂的数据结构,在它们的操作类函数的开始和结尾进行性质检查,所以个人想来,数据不变量可以算作是个扩大、统一版的前置、后置条件断言。
Zeller教授举了两个例子。一个是时间炸弹——平常玩潜伏的缺陷代码(遵循Zeller教授的观点,尽量不用bug一词),但一到关键时候,就会迫不及待地蹦跶出来,把你炸个焦头烂额。所以用数据不变量来严密监控之。随便吐槽一句,《潜伏》结局余则成学母鸡这个举动也太显眼了吧?
二是复杂的红黑树。红黑树要保持一致的性质就多了,Zeller教授一下就写出了5个检查函数,略晕。
另外还存在一个系统不变量,定义是在整个执行过程中保持不变的性质。呃,这个定义相当之含糊。我想不到特别适当的例子。Zeller教授举的是 C/C++内存溢出。但是我觉得防止内存溢出不能算作是一个性质,故而认为这个例子举得不恰当。
讲了这么多有的没的,归根到底,还是只关心怎么用,有没有比较推荐的使用方式。Zeller教授推荐步骤:
1、定义数据不变量。根据数据结构的性质,确定数据不变量,检查对数据结构的操作,尽早发现错误。
2、定义前置条件。检查函数参数的性质,相对来说,比较容易找到适当的前置条件。
3、定义后置条件。检查返回结果。在较难确定的条件下,后置条件可以相对放宽松些。
4、系统不变量则是根据程序需要来定义。
而如何自动推导不变量条件,Zeller教授推荐一个工具Daikon,编程练习写个简单版的Daikon。这个工具的核心思想是通过多次运行,用运行中函数的每个参数、返回结果的值,在工具的模式库中进行匹配。匹配上的模式保留,不匹配的删掉。很多次运行并分析后,留下的模式就作为参考的不变量条件。
思想很简单,穷举加匹配,重点就是看模式库中是否存在需要的模式了。库中模式越多,找到正确不变量条件的机会就越高,结果也就是花费时间越多。个人感觉,在对代码熟悉、业务熟悉的条件下,比如深刻理解了需求后,写出的代码,自己动脑寻找的不变量条件,应该要比这个自动工具的质量高。
使用断言还有一些注意事项:
1、断言也是费时的,尤其是检查内容比较复杂时,性能影响越大。所以可以关掉。
2、断言的条件中,应该只含有结果、getter一类,而不应该有设置器(setter)等进行操作的函数或语句。
3、断言不该用于检查公共前置条件。看不明白是吧?大概就是说,一定要检查的一些内容不应该用断言,因为断言可能被关掉。
Zeller教授举的是第三方输入,我不太熟悉。我就改举java里的IO,或是所有语言里打开文件的操作。为防止打开文件失败,一定要用if 或 try ... Catch语句来检查打开状态,否则一旦断言被关掉,这个后果……反而会出错。
最后就是来讨论下,为什么要用断言异常了。C/C++和Python里虽然断言默认是打开、支持的,但我很少用过。而Java里更是默认不使用断言异常。就像上面说的,可以用if或try...catch 来代替断言。断言可有两个缺点,一是影响性能,二是对用户不友好,你看,一旦触发断言,程序90%跟你说不玩了,这太不友好了。
先列Zeller教授举的断言三优点:
1、程序及时退出,哪怕只是小错误而退出,也比坏数据好,因为坏数据不知道会造成什么样的后果。很多人说的史上最昂贵的bug,阿丽亚纳五号运载火箭,就因为惯性制导系统无法将一个64位的数据转换到16位格式而烧掉了5亿美元。
Zeller教授说,本来开发时是有对格式转换进行检查的断言的,结果产品中因为考虑性能问题,能关掉了这些断言。另外即使断言被触发,这火箭的软件系统也有足够优秀的异常处理机制来继续工作。所以可能就因为节省了这么一些断言,而创造了世上最奢侈的烟花。和火箭、航天飞机放的烟花比起来,北京奥运的烟花花费确实算不上多……
2、断言可以让调试更简单。理由之前说过,更早地发现错误,更少的bug位置。
3、方便回溯缺陷。从出错断言开始,往回找,和2差不多的。
不过,Zeller教授也承认可以关闭一些影响性能的断言。拿红黑树来说,没必要在一次时间复杂度O(log n) 的插入操作的前面,分别进行时间复杂度为O(n)的遍历操作,就为了检查是否存在环这一性质。这样的断言没必要。
再来说说我的理解。首先是为什么if和try...catch不能代替断言,也就是为什么还要用断言,这么一个不友好的语句。
个人理解,因为一个最简单的断言函数大概就是,如果断言条件为假,则抛出异常。其实也就是一个if语句能完成的事。但是一个简单的if语句抛出的异常所能显示的信息,不如标准的断言异常的信息多。而一个assert(condition)在很多时候从便捷上、作用上都高于一个if (condition) throw XXX; 所以If 不能代替断言。
而try...catch的情况相似,除了像IO等操作可能已经有内置的异常机制,面对新的异常条件时,同样要用if(condition)throw 异常,或assert(condition)来抛出异常,方能catch到,用if的话,也就可能需要定义新的异常类型,更加不如断言来得方便。当然try...catch和断言功能上重叠得不多,更加没有取代的可能了。
try...catch更像是断言的母亲,在断言捣蛋、对用户不好的时候,她来揪着断言的小耳朵,给用户赔礼道歉。
这一单元就这么简单:
会用断言
勤用断言
善用断言
Udacity调试课笔记之断言异常的更多相关文章
- 菜农群课笔记之ICP与ISP----20110412(整理版)
耗时一上午时间对HOT大叔昨晚的群课内容进行温故并整理,现将其上传,若想看直播可到下面链接处下载:http://bbs.21ic.com/icview-229746-1-1.html 成 ...
- udacity android 学习笔记: lesson 4 part b
udacity android 学习笔记: lesson 4 part b 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...
- udacity android 实践笔记: lesson 4 part b
udacity android 实践笔记: lesson 4 part b 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...
- udacity android 学习笔记: lesson 4 part a
udacity android 学习笔记: lesson 4 part a 作者:干货店打杂的 /titer1 /Archimedes 出处:https://code.csdn.net/titer1 ...
- Elasticsearch7.X 入门学习第一课笔记----基本概念
原文:Elasticsearch7.X 入门学习第一课笔记----基本概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...
- 清华大学ucore操作系统课笔记
操作系统 清华大学ucore操作系统课笔记 全文思维导图 1. 操作系统概述 1.1 什么是操作系统? 操作系统的定义 没有公认的精确定义 一个控制程序 一个系统软件 控制程序执行过程,防止错误和计算 ...
- OllyICE 调试的程序无法处理异常 解决方法
问题描述 在用OllyICE打开可执行文件时出现如下图所示错误 解决方法 1. 选项 -> 调试设置 , 打开调试选项 2. 切换到 异常 页签 3. 取消勾选 忽略(传递给程序)以下异常: 单 ...
- OD调试学习笔记7—去除未注册版软件的使用次数限制
OD调试学习笔记7—去除未注册版软件的使用次数限制 本节使用的软件链接 (想自己试验下的可以下载) 一:破解的思路 仔细观察一个程序,我们会发现,无论在怎么加密,无论加密哪里,这个程序加密的目的就是需 ...
- w2wp.exe 已附加有调试器,但没有将该调试器配置为调试此未经处理的异常
一.问题描述 昨天系统联调,用到了VS2010 附件进程,把w2wp.exe 进程添加到vs2010 的调试进程中,这样其他系统访问我们系统,就可以捕获断点进行调试 但是,今天F5 调试的时候,发现直 ...
随机推荐
- My way on Linux - 知识梳理计划
知识梳理计划图 近期计划把自己学习的工作中用到的Linux知识梳理下,敬请期待.
- WebApi2官网学习记录---异常处理
HttpResponseException 当WebAPI的控制器抛出一个未捕获的异常时,默认情况下,大多数异常被转为status code为500的http response即服务端错误. Http ...
- EasyUI layout动态设置Split属性
switch (rowData.ISREGISTERTASK) { case 0: 显示north分割线 $('#RightContent').la ...
- Android与JS混编(js调用android相机)
参考android相机调用,http://blog.csdn.net/yanzi1225627/article/details/33028041/,谢谢 相机怎么调用就不做赘述了,下面是js调用 ...
- win7添加usb3.0驱动(错误代码1392,文件或目录损坏且无法读取)
Win7添加usb3.0驱动 之前一直按照网上的方法执行dism命令挂载时,总是失败,错误代码1392,显示原因是文件或目录损坏且无法读取.这个错误以前在装机时老是出现导致系统安装不成功,在BIOS中 ...
- c# 中的线程和同步
一.新建线程的3种方法 a)异步委托:b)Thread类:c)线程池: 二.异步委托 1.简单使用,检查委托是否完成其任务 a) 通过 BeginInvoke() 的返回值IAsyncResult ...
- 一个经试用效果非常不错的数据库连接池--JAVA
前言: 虽说现在许多企业级的应用服务器均自己带有数据库连接池功能,就连 Tomcat 也支持了这种功能.然而在许多时候,我们还是要使用数据库连接池,如:访问数据库的 Java 桌面应用程序等.这个数据 ...
- 影响MySQL性能的五大配置参数
我们今天主要和大家分享的是对MySQL性能影响关系紧密的五大配置参数,以下就是文章的具体内容描述,希望会给你带来一些帮助在此方面. 以下的文章主要是对MySQL性能影响关系紧密的五大配置参数的介绍,我 ...
- hadoop调优之一:概述
hadoop集群性能低下的常见原因 (一)硬件环境 1.CPU/内存不足,或未充分利用 2.网络原因 3.磁盘原因 (二)map任务原因 1.输入文件中小文件过多,导致多次启动和停止JVM进程.可以设 ...
- eclipse添加xsd
图片参考 http://wenku.baidu.com/link?url=DFHWF_yD-M-GCt2tfjs1npPs1xhNlyxik7i_pCBjw3oVlbssYrMvLNucuUpKg75 ...