《软件构造》第七章复习要点

一.健壮性和正确性

本节在1-2节的基础上,重申了健壮性和正确性的重要性,澄清了二者之间的差异,并指明了在软件构造中处理二者的典型技术(防御式编程、异常处理、测试、调试等)

1 什么是正确性和健壮性?

健壮性:系统在不正常输入或不正常外部环境下仍能够表现正常的程度

面向健壮性的编程:处理未期望的行为和错误终止;即使终止执行,也要准确/无歧义的向用户展示全面的错误信息;错

误信息有助于进行debug

正确性:程序按照规约加以执行的能力, 是最重要的质量指标!

正确性:永不给用户错误的结果

健壮性:尽可能保持软件运行而不是总是退出

一些对比:

正确性倾向于直接报错(error),健壮性则倾向于容错(fault-tolerance)

健壮性:
让用户变得更容易:出错也可以容忍,程序内部已有容错机

正确性:

扫描二维码关注公众号,回复: 1705992 查看本文章

让开发者变得更容易:用户输入错误,直接结束。(不满足precondition的调用)

Reliability(可靠性)。系统在规定的条件下执行其所需功能的能力,无论何时需要——在故障之间有很长的平均时间。

可靠性=健壮性+正确性

改进健壮性和正确性的步骤
步骤0:使用断言,防御性编程,代码审查,正式的验证等编写代码以实现正确性和健壮性目标
步骤1:观察故障症状(内存转储,堆栈跟踪,执行日志,测试)
步骤2:识别潜在的错误(bug本地化、调试)

步骤3:修复错误(代码修改)

2 如何衡量正确性和健壮性?

Mean time between failures (MTBF) 外部观察角度

MTBF (平均失效间隔时间):是系统在运行期间固有故障之间的预期运行时间。

Residual defect rates 内部观察角度(间接)

 Residual defect rates  残余缺陷率 refers to “bugs left over after the

software has shipped” per KLOC:  每千行代码中遗留的bug

二、异常

1.Throwable

在Java编程语言中,异常对象始终是可抛出类的实例。


2.Runtime异常和其他异常

异常等级也分为两个分支:

-从RuntimeException派生的异常。  运行时异常:由程序员在代码里处理不当造成

-其他异常:由外部原因造成

继承RuntimeException的异常包括如下问题:
-越界数组访问

-空指针访问

3.Checked异常和Unchecked异常


Checked Exceptions:需要从Exception 派生出子类型,编译器可帮助检查你的程序是否已抛出或处理了可能的异常,必须捕获并指定错误处理器handler,否则编译无法通过

Unchecked:Errors and Runtime Exceptions:  从RuntimeException 派生出子类型,可以不处理,编译没问题,但执行时出现就导致程序失败

 Declaring exceptions (throws) 声明“本方法可能会发生XX异常”
– Throwing an exception (throw) 抛出XX异常

– Catching an exception (try, catch, finally) 捕获并处理XX异常

-如果客户端可以通过其他的方法恢复异常,那么采用checked exception;
– 如果客户端对出现的这种异常无能为力,那么采用unchecked exception;

– 异常出现的时候,要做一些试图恢复它的动作而不要仅仅的打印它的信息。

  尽量使用unchecked exception 来处理编程错误

错误可预料,但无法预防,但可以有手段从中恢复,此时使用checkedexception 。如果做不到这一点,则使用unchecked exception

4.Checked异常的处理机制

方法要在定义和spec 中明确声明所抛出的全部checked exception,没有抛出checked 异常,编译出错,Unchecked 异常和Error 可以不用 处理

如果子类型中override 了父类型中的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型更宽泛

子类型方法可以抛出更具体的异常,也可以不抛出任何异常。如果父类型的方法未抛出异常,那么子类型的方法也不能抛出异常。

5.构建异常类

Eg:public class FooException extends Exception {
public FooException() { super(); }
public FooException(String message) { super(message); }
public FooException(String message, Throwable cause) {
super(message, cause);
}
public FooException(Throwable cause) { super(cause); }

}

当异常抛出时,方法中正常执行的代码被终止。  如果异常发生前曾申请过某些资源,那么异常发生后这些资源要被恰当的清理

使用finally

不管程序是否碰到异常,finally都会被执行

三、断言和防御式编程

断言:在开发阶段的代码中嵌入,检验某些“假设”是否成立。若成立,表明程序运行正常,否则表明存在错误。增

强程序员对代码质量的信心:对代码所做的假设都保持正确。断言主要用于开发阶段,避免引入和帮助发现bug。实际运行阶段,不再使用断言。避免降低性能

使用断言的主要目的是为了在开发阶段调试程序、尽快避免错误

  使用异常来处理你“预料到可以发生”的不正常情况

使用断言 处理“绝不应该发生”

defensive programming:检查前置条件是防御式编程的一种典型形式

对来自外部的数据源要仔细检查,例如:文件、网络数据、用户输入等

对每个函数的输入参数合法性要做仔细检查,并决定如何处理非法输入

  类的public 方法接收到的外部数据都应被认为是dirty 的,需要处理干净再传递到private 方法——隔离舱g

“隔离舱”外部 的函数应使用异常处理 ,“隔离舱”内的函数应使用断言。


猜你喜欢

转载自blog.csdn.net/weixin_39627422/article/details/80763137