软件构造复习总结(3)

健壮性和正确性:

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

正确性:程序按照spec加以执行的能力

面向健壮性的编程:

-处理未期望的行为和错误终止

-即使终止执行,也要准确/无歧义的向用户展示全面的错误信息

-错误信息有助于进行debug

-返回给用户的错误提示信息要详细、准确、无歧义

内部错误与异常:

内部错误:程序员通常无能为力,一旦发生,想办法让程序优雅的结束

1.用户输入错误

2.设备错误

3.物理限制

异常:你自己程序导致的问题,可以捕获、可以处理

异常处理

Java中Exception可以被分为两个部分,蓝色的运行时异常和绿色的其他异常。

运行时异常:由程序员在代码里处理不当造成,在源代码中引入了故障,而如果在代码中提前进行验证,这些故障就可以避免。动态类型检查的时候会发现这种异常,而一旦出现,代码就必然有错误,可以通过调试解决。

其他异常:由外部原因造成,程序员无法完全控制的外在问题所导致的,即使在代码中提前加以验证,也无法完全避免失效发生。

Checked异常、Unchecked异常:

Unchecked异常:客户端无法再继续处理的异常,代表代码中的错误

可以不处理,编译没问题,但执行时出现就导致程序失败,代表程序中的潜在bug,类似于编程语言中的dynamic type checking

Checked异常:客户端能够进行处理的异常,而对开发者来说错误可预料但不可预防,它的出现已经脱离了程序能够掌控的范围。

必须捕获并指定错误处理器handler,否则编译无法通过,类似于编程语言中的 static type checking

处理checked异常时,可以使用如下关键词:

– try &– catch 测试并捕获异常

 – finally处理异常时释放资源:当异常抛出时,方法中正常执行的代码被终止,如果异常发生前曾申请过某些资源,则清理异常发生后的这些资源。

 – throws抛出异常(声明程序可能会发生此异常)

 – throw 抛出异常(实际抛出)

流程则基本如下:

– Declaring exceptions (throws) 声明“本方法可能会发生XX异常”

 – Throwing an exception (throw) 抛出XX异常

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

String readData(Scanner in) throws EOFException // 声明:本函数可能发生该异常

{

       . . .

       while (. . .)

       {

              if (!in.hasNext()) // EOF encountered

              {

                     if (n < len)

                            throw new EOFException(); // 异常在这里发生了

              }

              . . .

       }

       return s;

}

LSP&异常

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

子类型方法可以抛出更具体的异常,也可以不抛出任何异常——异常可以协变

如果父类型的方法未抛出异常,那么子类型的方法也不能抛出异常

断言与防御式编程

防御式编程的基本思想

最好的防御就是不要引入bug,如果无法避免,则尝试着将bug限制在最小的范围内或限定在一个方法内部,不扩散

Fail fast:尽快失败,就容易发现、越早修复

断言:

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

断言即是对代码中程序员所做假设的文档化,也不会影响运行时性能(在实际使用时,assertion都会被disabled)

语法:assert condition : message;

所构造message在发生错误时显示给用户,便于快速发现错误所在

断言与异常的作用区别:

断言用于提高“正确性”,作用于程序的内部,处理“绝不应该发生”的情况

异常用于提高“健壮性”,作用于程序的外部,处理“能预料会发生”的情况

assert使用场所:

内部不变量:判断某个局部变量应该满足的条件,assert x > 0

表示不变量:checkRep()

控制流不变量:例如,若不想让程序走向switch-case的某个分支,则可以用断言直接在分支上assert false;

方法的前置条件:判断传入参数是否满足前置条件

方法的后置条件:判断结果时候满足后置条件

由于Assert运行时非常影响效率,一般将其应用移除出代码。

防御性编程:

防御性编程是一种防御性设计,旨在确保软件在不可预见的情况下保持安全性

对来自外部的数据源要仔细检查,例如:文件、网络数据、用户输入等,以从非法输入中保护自己

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

Barricade 设置路障:一种损失控制策略

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

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值