【软件构造】第七章第三节 断言和防御性编程

第七章第三节 断言和防御性编程

本节:第2种技术——断言、防御式编程

Outline

  • 断言

    • 什么是断言
    • 断言的应用场景
  • 防御式编程(不是考点,不加叙述)

Notes:

## 断言

【什么是断言】

  • 作用:允许程序在运行时检查自己,测试有关程序逻辑的假设,如前置条件、后置条件、内部不变量、表示不变量、控制流不变量等
  • 目的: 为了在开发阶段调试程序、尽快避免错误
  • 使用阶段:
    • 断言主要用于开发阶段,避免引入和帮助发现bug
    • 实际运行阶段, 不再使用断言
    • 软件发布阶段,禁用断言避免影响性能。

【应用场景】

  • 输入参数或输出参数的取值处于预期范围
  • 子程序开始执行(结束)时,文件或流处于打开(关闭)状态
  • 子程序开始执行(结束)时,文件或流的读写位置处于开头(结尾)
  • 文件或流已打开
  • 输入变量的值没有被子程序修改
  • 指针非空
  • 传入子程序的数组至少能容纳X个元素
  • 表已初始化,存储着真实的数据
  • 子程序开始(结束)时,容器空(满)
  • 一个高度优化过的子程序与一个缓慢的子程序,结果一致
  • 断言只在开发阶段被编译到目标代码中,而在生成代码时不编译进去。使用断言的指导建议:
  • 用错误处理代码来处理预期会发生的状况,断言不行!
  • 避免把需要执行的代码放入断言中(如果未编译断言呢?)
  • 用断言来注解并验证前条件和后条件
  • 对于高健壮性的代码,应该先用断言,再处理错误

【注意】

  • 编译时加入-ea(enable assertion)选项运行断言,-da(disable assertion)关闭断言
  • 条件语句或开关没有涵盖所有可能的情况,最好使用断言来阻止非法事件
  • 可以在预计正常情况下程序不会到达的地方放置断言:assert false
  • 断言有代价,需慎用,一般用于验证正确性,处理绝不应该发生的情况
  • 不能作为公共方法的检查,也不能有边界效应

 【断言和异常的对比】

  • 用异常处理技术来处理你“希望发生”的不正常情况
  • 用断言来处理“不希望发生”的情况;断言的方式处理一定是发生了错误
  • 不要把业务逻辑(执行代码)放到断言里面去处理
  • 参数检查通常是方法发布的规范(或契约)的一部分,无论断言是启用还是禁用,都必须遵守这些规范。
    • 如果参数来自于外部(不受自己控制),使用异常处理
    • 如果来自于自己所写的其他代码,可以使用断言来帮助发现错误(例如postcondition就需要)

## 防御性编程(不是考点,不加叙述)

  • 防御式编程的主要思想就是,子程序不应该因为传入错误数据而被破坏。其核心想法就是要承认程序都会有问题,都需要被修改。
  • 处理外来垃圾的方法:检查所有来自外部的数据值,检查子程序的输入参数值,决定如何处理数据。
  • 防御式编码的最佳方式就是一开始代码中引入错误,使用迭代式设计、编码前先写伪代码、写代码前先写测试用例、底层设计检查等活动都可以防止。

原文地址:https://www.cnblogs.com/hithongming/p/9195142.html

时间: 2024-07-30 18:57:30

【软件构造】第七章第三节 断言和防御性编程的相关文章

软件构造 第七章第三节 断言和防御性编程

第七章第三节 断言和防御性编程 断言:在开发阶段的代码中嵌入,检验某些"假设"是否成立.若成立,表明程序运行正常,否则表明存在错误. 可用于检查: 内部不变量: 表示不变量: 控制流不变量 方法的前置条件 方法的后置条件 断言主要用于开发阶段,避免引入和帮助发现bug 实际运行阶段, 不再使用断言 软件发布阶段,禁用断言避免影响性能. 断言?Correctness 错误/异常处理?Robustness Defensive Programming 对来自外部的数据源要仔细检查,例如:文件

软件构造 第三章第三节 抽象数据型(ADT)

软件构造 第三章第三节 抽象数据型(ADT) Creators(构造器): 创建某个类型的新对象,?个创建者可能会接受?个对象作为参数,但是这个对象的类型不能是它创建对象对应的类型.可能实现为构造函数或静态函数.(通常称为工厂方法) t* ->  T 例子:Integer.valueOf( ) Producers(生产器): 通过接受同类型的对象创建新的对象. T+ , t* -> T 例子:String.concat( ) Observers(观察器): 获取抽象类型的对象然后返回一个不同类

软件构造 第七章第四节 调试

第七章第四节 调试 [bug的常见类型] 数学bug:例如 零除法,算术溢出 逻辑bug:例如 无线循环和无限递归 源头bug:例如 使用了为被定义的变量.资源泄漏,其中有限的系统资源如内存或文件句柄通过重复分配耗尽而不释放.缓冲区溢出,其中程序试图将数据存储在分配存储的末尾. 团队工程bug:例如 评论过时或者评论错误.文件与实际产品的区别 ## 调试的基本过程 Debug是测试的后续步骤:测试发现问题,debug消除问题:当防御式编程和测试都无法挡住bug时,我们就必须进行debug了: D

软件构造 第六章第三节 面向可维护的构造技术

第六章第三节 面向可维护的构造技术 基于状态的构造技术 状态模式(State Pattern) 备忘录模式(Memento Pattern) Grammar-based construction 使用grammar判断字符串是否合法,并解析成程序里使用的数据结构 . 正则表达式 通常是递归的数据结构 . terminals 终止节点.叶节点 nonterminal 非终止节点(遵循特定规则,利用操作符.终止节点和其他非终止节点,构造新的字符串) 三个基本语法的操作符: 连接,不是通过一个符号,而

软件构造 第七章第二节 错误与异常处理

第七章第二节 错误与异常处理 内部错误:程序员通常无能为力,一旦发生,想办法让程序优雅的结束 异常:你自己程序代码发生的,可以捕获处理 [Error] Error类描述很少发生的Java运行时系统内部的系统错误和资源耗尽情况(例如,VirtualMachineError,LinkageError). 对于内部错误:程序员通常无能为力,一旦发生,想办法让程序优雅的结束 Error的类型: 用户输入错误 例如:用户要求连接到语法错误的URL,网络层会投诉. 设备错误 硬件并不总是做你想做的. 输出器

软件构造 7-3 断言和防御性编程

断言和防御性编程 目录回忆:设计和抽象数据类型 断言 什么断什么不断 使用断言的指导方针 防御性编程 防御型编程的技巧 回忆 第一层防御:使bugs不可能 最好的防御bug的方法就是在设计的时候就尽量避免bug - 静态检查:在编译的时候,可以抓住许多bug - 动态检查:比如数组溢出 -  不变量:不变量 -  防御性拷贝 - 引用不变量:by final 第二种防御: 如果bug不能被阻止,则限制在尽可能小的范围内 问题越早发现,越容易被修复 利用assertion检查前置条件的满足性如上图

【软件构造】第二章第二节 软件构造的过程、系统和工具

第二章第二节 软件构造的过程.系统和工具 Outline 广义的软件构造过程 编程 静态代码分析 动态代码分析 调试与测试 重构 狭义的软件构造过程 构造系统:经典BUILD场景 构造系统的组件 构造过程和构造描述 Java编译工具 子目标和结构变体 构造工具 Notes ## 广义的软件构造过程 [编程(Coding)] 开发语言:如Java.C.Python 使用IDE(集成开发工具)的优势(组成) 方便编写代码和管理文件(有代码编辑器,代码重构工具.文件和库(Library)管理工具) 能

【软件构造】第一章 软件构造基础(2)

二.软件构造的质量目标 1. 外部属性(主要):影响用户感受,如外观.速度等 (1)正确性:符合规格范围和计划目标 ·只保证各个层面的正确性(假设调用正确) ·检验与调试 ·防御性编程 ·形式化编程 (2)健壮性:响应规格范围外的异常情况 ·提示错误信息 ·正常退出或降级 (3)可扩展性:提供增加新功能的空间 ·固化需求以规避风险 ·设计简洁.离散化 (4)可复用性:使软件模块能够被其他程序使用 ·模式固化 (5)兼容性:跨平台.跨软件交互 ·使用标准文件格式.数据结构.接口,保持一致性 ·定义

软件构造 第三章第二节 软件规约

第三章第二节 软件spec 客户端无需阅读调用函数的代码,只需理解spec即可. 精确的规约,有助于区分责任,给"供需双方"确定了责任,在调用的时候双方都要遵守. @param @return @throws 例子: Behavioral equivalence (行为等价性) 根据规约判断是否行为等价 与实现无关! 如果两个函数符合这个规约,故它们等价. Specification Structure 前置条件(precondition):对客户端的约束,在使用方法时必须满足的条件.