软件构造复习 Chapter 6

6.1 健壮性与正确性

健壮性:保证程序可以正常进行下去(容错)

  1. 面向内部的接口倾向于:正确性
    面向外部的接口倾向于:健壮性
  2. error(程序员犯的错误)——> defect/fault/bug(缺陷,bug的根源)——> failure(失效,运行时的外部表现)
  3. 衡量
    1. 外部观察角度
      平均失效间隔时间(MTBF):失效时间+修复时间
    2. 内部观察角度
      残余缺陷率:每千行代码中遗留的bug数量
  4. 编程时提高健壮性与正确性的方法:
    assertion,exception,error,defensive programming(防御式编程)

6.2 错误与异常处理(**)

注:异常用来提高程序健壮性,断言用来提高程序正确性

  1. error与异常

    error:外部因素导致的
    异常:

    1. 运行时异常:程序写错导致的
    2. 其他异常:client调用错误导致的
      (一般异常处理的不是程序出错,而是client调用错误
  2. 出现异常时会层层向上(调用者)找是否可以处理出现的异常,直到找到。

3. checked异常、unchecked异常

在这里插入图片描述
1. Unchecked异常:error + Runtime异常
不需要在编译时用try…catch等机制处理,但若执行时出现会导致程序失败
2. Checked异常
必须捕获指定错误处理器handler,否则编译无法通过
3. 常见Unchecked异常
ArrayIndexOutOfBoundsException——使用时超出数组边界
NullPointerException——使用空指针时
NumberFormatException——将字符串转换为数值类型失败时
ClassCastException——强制转换对象引用失败时

  1. 关键字
    try
    catch
    finally(不管正确路径还是错误路径,finally下的语句都要执行)
    throws声明可能会发生的异常)
    throw(抛出异常)
  2. 针对checked异常编译器检测的两种方式
    1. try catch捕获
    2. 方法名后加上对应的throws,对异常进行抛出
      在这里插入图片描述
  3. Unchecked异常也可以throws声明或try/catch捕获,但不应该这么做
checked异常Unchecked异常
客户端可以通过其他的额方法恢复异常客户端无能为力
可预料不可预防可预料可预防
除了右边以外的派生派生于Error或者RuntimeException的异常

1 尽量使用unchecked异常处理编程错误(eg:NullPointerException,IllegalArgumentException)
原因:不用客户端代码显示的处理
2. 如果client对某种异常无能为力,可以把它转变成一个unchecked异常,程序被挂起并返回客户端异常信息在这里插入图片描述
3. 针对每一个checked 异常,创建checked异常的子类,采用继承的方式使客户端可以明确失败原因并去克服。
4. 对于RuntimeException,不需要定义子类不需要继承,就用java提供的几种异常即可在这里插入图片描述

8. throws

注:java中任何一个程序都不会显示的通过throws语句抛出		RuntimeException(正确)
  1. 需要在方法的**spec中明确写清本方法抛出的*所有*checked exception**,以便于调用该方法的client加以处理。

下图即在规约中明确写出
在这里插入图片描述
在这里插入图片描述
2. 抛出Unchecked异常程序不会报错,但这种写法是不应该的。
3. 使用throws的两种情况:
i. 调用的函数抛出checked exception(处理不了就往上抛)
ii. 自己当前的方法抛出checked exception

8.4 LSP原则对异常的要求

  1. 如果父类型抛出异常,则相对应的子类型要么**不抛出异常**,要么抛出的异常比父类型抛出的**一样/更具体**。
  错误举例:父抛 FileNotFoundException,子抛 IOException(x)
  2. 如果父类型中的方法没有抛出异常,那么子类型中的方法**必须捕获所有的checked exception**

9. throw

  1. 两种使用方式:
    1. throw new EOFException();
    2. EOFException e = new EOFException();
      throw e;
  2. **throw和throws一般在方法中是一一对应的(但是不写throws也不会报错)**或者throw也可以与try/catch一一对应
    在这里插入图片描述
  3. 自己构造异常类输出错误的现场信息方法:
    利用Exception的构造函数
    在这里插入图片描述

9.4 throw一个异常的步骤

  1. 找到一个可表达错误的异常类/构造一个新的异常类

  2. 构造Exception类的实例,写入错误信息

  3. 抛出它

    【注意:关于自己构造异常类的代码】
    1.
    在这里插入图片描述
    2. 注意throws和throw的对应
    在这里插入图片描述
    3. 用辅助方法记录“案发现场信息”

10. catch

  1. 获取异常具体信息的两种方法
    1. e.getMessage()
    2. e.getClass().setName()
  2. catch多个类型异常的优先级
    在这里插入图片描述
    离try语句越近异常类越具体
  3. rethrowing 重新抛出异常
    即在catch中抛出异常
    重抛异常会把异常抛给上一级环境中的异常处理程序。同一个 try 块的后续 catch 子句将被忽略。此外,异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。
public static void f() throws Exception {
	System.out.println("a_mark");
	throw new Exception("b_mark");
}

public static void g() throws Exception {
	try {
		f();
	} catch (Exception e) {
		System.out.println("c_mark");
		e.printStackTrace(System.out);
		throw e;
	}
}  
public static void main(String[] args) {
	try {
		g();
	} catch (Exception e) {
		System.out.println("e_mark");
		e.printStackTrace(System.out);
	}
}


在这里插入图片描述
目的:更改exception的类型,方便client端获取错误信息。(注:加上se.initCause(e)是为了保留根原因,能调用se.getCause()得到异常e)

11. finally

无论是否发生异常,finally后的部分都会被执行

  1. 执行顺序问题
    1. 当程序出现异常并捕获
    在这里插入图片描述
    不会经过2(1的时候就中断了)
    2. 当程序出现异常但没有被捕获
    在这里插入图片描述
    顺序是1、5——没有6的原因是程序没有被捕获,一般会找调用方看是否能处理异常
    3. 异常被捕获了,但是catch中又抛出了一个异常
    顺序为1、3、5
    4. 带资源的try(TWR)
    可以带多个资源
    在这里插入图片描述
  2. Stack Trace
    1. 注意顺序
    2. 打印调用栈
      1. throwable提供的printStackTrace(接收类型PrintWriter(接收类型StringWriter)))
        在这里插入图片描述
      2. 或把调用栈的内容放在数组里面 在这里插入图片描述

6.3 断言与防御机制

程序开发的时候才需要断言!

  1. 两种形式
    assert conditon
    assert condition : message;
    例如:assert x > 0 : " x is " + x ;
  2. 断言的检测内容
    1. 内部不变量
    2. 表示不变量
    3. 控制流不变量
    4. 方法的前置条件(通常选择用异常写)
      在这里插入图片描述
    5. 方法的后置条件
      在这里插入图片描述
      B处应该为:在这里插入图片描述

3. 断言VS异常

1.断言能做的,异常都能做(但是断言可以自动关闭)
2.

private一般用断言查
public一般用异常查
返回值用断言检测
  1. 防御式编程
    1. 保证对不正确输入也要有结果
    2. 路障设置(代理模式——用来校验的功能)

6.4 debugging 代码调试

提高程序的核心手段不是测试/debug,而是前文的模式方法

  1. 复现bug
    保证环境一致
  2. 诊断bug
    1. print出来
      注:软件release出去的时候,所有用于debug的print语句都要去除或禁用
      实际操作中可以用一个方法专门用来打印错误信息,release时禁用方法里那条print语句即可
      在这里插入图片描述
    2. 看日志(日志可以设置级别)
      例:用Hashset打印在这里插入图片描述
  3. 围狼算法(分治)
  4. 切片
  5. 寻找差异
    1. 分析版本提交的不同
    2. 基于差异的调试(比较不同测试用例覆盖代码的差异)
    3. 其他差异(软硬件环境…)
  6. 符号化执行
  7. debug工具
    1. 暴力搜索

    7.2. stack trace

    在这里插入图片描述
    例:判断Stack Trace的输出
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值