HIT软件构造课程复习笔记(六)

6.1 健壮性与正确性

什么是健壮性与正确性

健壮性:系统在不正常输入或不正常外部环境下仍能够表现正常的程度
面向健壮性的编程:处理未期望的行为和错误终止,即使终止执行,也要准确/无歧义的向用户展示全面的错误信息,这有助于进行debug
健壮性原则:总是假定用户恶意、假定自己的代码可能失败;把用户想象成白痴,可能输入任何东西;对别人宽容点,对自己狠一点,对自己的代码要保守,对用户的行为要开放。封闭实现细节,限定用户的恶意行为,考虑极端情况,没有“不可能” ,这样避免给用户太大压力, 帮助用户承担一些麻烦

正确性:程序按照spec加以执行的能力,是最重要的质量指标
相较于健壮性,正确性永不给用户错误的结果,健壮性尽可能保持软件运行而不是总是退出;正确性倾向于直接报错(error),健壮性则倾向于容错(fault-tolerance);正确性让开发者变得更容易,用户输入错误,直接结束。(不满足precondition的调用)健壮性让用户变得更容易,出错也可以容忍,程序内部已有容错机制。
对外的接口,倾向于健壮;对内的实现,倾向于正确;我们要在内外部之间做好隔离,防止“错误”扩散

可靠性=健壮性+正确性
error:程序员犯的错误
defect:缺陷,bug的根源
fault:defect约等于fault+bug
failure:失效,运行时的外在表现
error->defect/fault/bug->failure
程序员犯错导致软件存在缺陷,导致软件运行时失效

提高软件健壮性与正确性的步骤:
step0:断言、防御式编程、代码复查、格式有效
step1:观察失败症状(内存转储,堆栈跟踪,执行日志,测试)
step2:识别潜在故障(确认bug位置、debug)
step3:修复错误(代码修改)

如何测量健壮性与正确性

平均失效间隔时间MTBF:系统在运行期间固有故障之间的预计运行时间。MTBF的定义取决于对系统故障的定义。
MTBF描述了一个可修复系统两次故障之间的预期间隔时间,而平均故障时间(MTTF)表示了一个不可修复系统的预期故障时间。

残余缺陷率:每千行代码中遗留的bug的数量(工业级1-10个)

6.2 错误与异常处理

Java中的错误和异常处理

Java错误与异常类:
在这里插入图片描述
内部错误:程序员通常无能为力,一旦发生,想办法让程序优雅的结束。包括用户输入错误、设备错误、物理限制。在大多数时候, 程序员不需要实 例化Error
异常:你自己程序导致的问题,可以捕获、可以处理

异常处理

异常:程序执行中的非正常事件,程序无法再按预想的流程执行 。将错误信息传递给上层调用者,并报告“案发现场”的信息,这是return之外的第二种退出途径,若找不到异常处理程序,整个系统完全退出。

运行时异常:由程序员在代码里处理不当造成(劣转换、数组越界、访问空指针)这是程序源代码中引入的故障所造成的,如果在代码中提前进行验证,这些故障就可以避免
其他异常:由外部原因造成,是程序员无法完全控制的外在问题所导致的,即使在代码中提前加以验证(文件是否存在),也无法完全避免失效发生。

异常处理:要么你解决,要么告诉编译器你解决不了,编译器可帮助检查你的程序是否已抛出或处理了可能的异常,但运行时异常和错误是不会被编译器检查的,只能修改和重构你的程序代码

unchecked异常:运行时异常+错误
不需要在编译的时候用try-catch等机制处理,编译没问题,但执行时出现就导致程序失败,代表程序中的潜在bug,类似于编程语言中的动态类型检测(在编程和编译的时候,IDE与编译器均不会给出任何错误提示)

checked异常:
必须捕获并指定错误处理器handler,否则编译无法通过,类似于编程语言中的静态类型检测。我们使用try-catch-finally模块捕获处理异常,throws声明本方法可能会发生某异常,throw抛出一个异常。(catch的异常自上而下由细变粗)

Unchecked异常也可以使用throws声明或try/catch进行捕获,但大多数时候是不需要的,也不应该这么做。当要决定是采用checked exception还是unchecked exception的时候,问一个问题:“如果这种异常一旦抛出,client会做怎样的补救?”如果客户端可以通过其他的方法恢复异常,那么采用checked exception;如果客户端对出现的这种异常无能为力,那么采用unchecked exception;异常出现的时候,要做一些试图恢复它的动作而不要仅仅的打印它的信息。

尽量使用unchecked exception来处理编程错误:因为unchecked exception不用使客户端代码显式的处理它们,它们自己会在出现的地方挂起程序并打印出异常信息。如果client端对某种异常无能为力,可以把它转变为一个unchecked exception,程序被挂起并返回客户端异常信息。不要创建没有意义的异常,client应该从checked exception中获取更有价值的信息(案发现场具体是什么样子),利用异常返回的信息来明确操作失败的原因。

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

对比:
在这里插入图片描述
Java方法可以在遇到无法处理的情况时抛出异常。“异常”也是方法和client端之间spec的一部分,在post-condition中刻画。程序员必须在方法的spec中明确写清本方法会抛出的所有checked exception, 以便于调用该方法的client加以处理。
自己的方法应该可能throws两种异常:你所调用的其他函数抛出了一个checked exception——从其他函数传来的异常;当前方法检测到错误并使用throws抛出了一个checked exception——你自己造出的异常;如果没有handler来处理被抛出的checked exception,程序就终止执行。(不要抛出错误和unchecked异常)

LSP:如果子类型中override了父类型中的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型更宽泛,子类型方法可以抛出更具体的异常,也可以不抛出任何异常,如果父类型的方法未抛出异常,那么子类型的方法也不能抛出异常。(强行为子类型化)子类型方法参数:逆变;子类型方法的返回值:协变。

利用Exception的构造函数,将发生错误的现场信息充分的传递给client。
throw new EOFException(String s);
一旦抛出异常,方法不会再将控制权返回给调用它的client,因此也无需考虑返回错误代码

自定义异常类:

checked异常例子:
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); }
}

unchecked异常extends RuntimeException即可,自定义异常类的时候可以添加辅助属性和辅助方法来更精确的描述异常情况。异常发生后,如果找不到处理器,就终止执行程序,在控制台打印出stack trace;抛出的异常也可以不在本方法内处理, 而是传递给调用方,由client处理(“推卸责任”)

如果父类型中的方法没有抛出异常,那么子类型中的方法必须捕获所有的checked exception,子类型方法中不能抛出比父类型方法更多的异常。e.getClass().getName() 可以获得异常对象的实际类型

重新抛出和链接异常:
本来catch语句下面是用来做exception handling的,但也可以在catch里抛出异常。这么做的目的是更改exception的类型,更方便client端获取错误信息并处理,但这么做的时候最好保留“根原因”:
catch (SQLException e) {
Throwable se = new ServletException(“database error”);
se.initCause(e);
throw se;
}
Throwable e = se.getCause();

finally模块:当异常抛出时,方法中正常执行的代码被终止,如果异常发生前曾申请过某些资源,那么异常发生后这些资源要被恰当的清理。无论异常是否被捕获,finally块中的代码一定会被执行。

Try-with-Resources语句:
try (Resource res = . . .) { work with res }
在try语句块执行完毕时会自动执行关闭已打开资源的操作

Stack trace:多级调用方法的记录由方法调用栈管理,异常会提交到JVM,JVM负责寻找解决该异常的handler,可以调用printStackTrace方法查看:
Throwable t = new Throwable();
StackTraceElement[] frames = t.getStackTrace();
for (StackTraceElement frame : frames)
//analyze frame

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值