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 调试的时候,发现直 ...
随机推荐
- Codeforces Round #260 (Div. 2)A. Laptops
A. Laptops time limit per test 1 second memory limit per test 256 megabytes input standard input out ...
- .NET基础拾遗(3)字符串、集合和流2
二.常用集合和泛型 2.1 int[]是值类型还是引用类型? .NET中无论是存储值类型对象的数组还是存储引用类型的数组,其本身都是引用类型,其内存也都是分配在堆上的.所有的数组类型都继承自Syste ...
- DIV+CSS 自适应布局
两栏布局,左边定宽200px,右边自适应.如何实现?我的第一个反应就是:用flex伸缩盒呀,然后balabala...说完之后,面试官说,还有没有别的方法?flex有些浏览器不支持嗯...我愣了一下, ...
- (转)Ajax的原理和应用
1.ajax技术的背景 不可否认,ajax技术的流行得益于google的大力推广,正是由于google earth.google suggest以及gmail等对ajax技术的广泛应用,催生了ajax ...
- html的空格显示距离问题
一.使用全角空格 全角空格被解释为汉字,所以不会被被解释为HTML分隔符,可以按照实际的空格数显示. 二.使用空格的替代符号 替代符号就是在需要显示空格的地方加入替代符号,这些符号会被浏览器解释为空格 ...
- win7 安装vs2010报错 Error code -939523550 for this component is not recognizedHi
When i try to install VS2010, Its not installing. I'm getting an error. It just try to install the ...
- 作为java应届生,面试求职那点事
找工作两星期多了.心情不爽,写点记录打发时间. 嘘~~自己的破事: 刚毕业,也过了实习,本理所应当的留在公司转正.可是为了谈了两年的女朋友回家见面.一切都顺利进行,妈妈也开心给了一万见面礼,一切都以 ...
- 2、 Spark Streaming方式从socket中获取数据进行简单单词统计
Spark 1.5.2 Spark Streaming 学习笔记和编程练习 Overview 概述 Spark Streaming is an extension of the core Spark ...
- DataSource
数据库连接池原理:在内存中开辟一段存储空间用来存储多个Connection连接,避免频繁的创建Connection,从而提高效率.代码如下: package jcbc.ds.test1; import ...
- 洛谷 P3397 地毯
P3397 地毯 题目背景 此题约为NOIP提高组Day2T1难度. 题目描述 在n*n的格子上有m个地毯. 给出这些地毯的信息,问每个点被多少个地毯覆盖. 输入输出格式 输入格式: 第一行,两个正整 ...