1 实验目标概述
本次实验重点训练学生面向健壮性和正确性的编程技能,利用错误和异常处理、断言与防御式编程技术、日志/断点等调试技术、黑盒测试编程技术,使程序可在不同的健壮性/正确性需求下能恰当的处理各种例外与错误情况,在出错后可优雅的退出或继续执行,发现错误之后可有效的定位错误并做出修改。
实验针对 Lab 3 中写好的 ADT 代码和基于该 ADT 的三个应用的代码,使用以下技术进行改造,提高其健壮性和正确性:
-
错误处理
-
异常处理
-
Assertion 和防御式编程
-
日志
-
调试技术
-
黑盒测试及代码覆盖度
2 实验环境配置
在eclipse的软件市场中搜索安装spotbugs
3 实验过程
3.1 Error and Exception Handling
3.1.1 处理输入文本中的三类错误
与Lab3中相比,readFileCreatFlightSchedule()只保留了添加读取的计划项和异常处理部分。readFileCreatFlightSchedule()中的解析文件内容并判断是否满足各种依赖关系的部分被抽取出成为了一个单独的方法entries(),当不满足条件时只需要抛出相应的异常信息即可。
3.1.1.1 存在不符合语法规则的语句
异常类 | 意义 |
---|---|
InherentFormatException | 文件中一个完整的计划项的固有的格式如“Flight:”等字段和大括号的异常 |
DateTimeFormatException | 日期时间格式异常 |
EntryNameFormatException | 航班号格式异常 |
AirportFormatException | 机场的名字含有不合法字符的异常 |
PlaneCodeFormatException | 飞机编号格式异常 |
PlaneAgeFormatException | 机龄格式异常 |
PlaneSeatsFormatException | 飞机座位格式异常 |
PlaneTypeFormatException | 飞机型号格式异常 |
抛出与处理:
利用正则表达式解析读入的字符串,如果匹配失败则抛出相应的异常。
date = s.substring(7, 17);
name = s.substring(18);
if (!s.substring(0, 7).matches(pattens[0]) || !s.substring(17, 18).matches(pattens[2]))
throw new InherentFormatException("第" + (fileLineNum + 1) + "行固定格式有误");
if (!date.matches(pattens[1]))
throw new DateTimeFormatException("第" + (fileLineNum + 1) + "行日期格式有误");
if (!name.matches(pattens[3]))
throw new EntryNameFormatException("第" + (fileLineNum + 1) + "行航班号格式有误");
抛出后不在方法内部处理,抛给上级方法,在上级方法中统一处理。
3.1.1.2 存在标签完全一样的元素
异常类:SameInfoEntryException
记录从文件中读取到的所有计划项,每读入一个新的计划项就遍历之前所有的计划项,找出相同航班号的计划项,然后判断航班日期,如果一样则抛出该异常。
与3.1.1.1相同,不在方法内部处理,抛给上级方法,在上級方法中统一处理。
// 同一个航班号
if (charOfpeName.equals(charOfName) && numOfpeName == numOfName) {
// 日期一样
if (peDate.equals(date))
throw new SameInfoEntryException("第" + (fileLineNum+1) + "行计划项的标签与之前的计划项完全一样");
3.1.1.3 各元素之间的依赖关系不正确
异常类 | 意义 |
---|---|
DepartureDateInconsistentException | 起飞日期和航班日期不一致异常 |
ArrivalDateInconsistentException | 降落日期和航班日期的差距大于一天异常 |
EntryInfoInconsistentException | 具有不同日期相同航班号的航班的起降机场和时间有差异的异常 |
PlaneInfoInconsistentException | 相同编号的飞机信息不一致异常 |
判断新计划项的日期是否满足依赖:
if (!startDate.equals(flightDate))
throw new DepartureDateInconsistentException("第" + (fileLineNum+1) + "行计划项的起飞日期和航班日期不一致");
if (!(endDate.equals(flightDate) || endDate.plusDays(-1).equals(flightDate)))
throw new ArrivalDateInconsistentException("第" + (fileLineNum+1) + "行计划项的降落日期和航班日期差距超过一天");
判断与新计划项相同航班号的起降具体时间和起降机场信息:
// 同一个航班号
if (charOfpeName.equals(charOfName) && numOfpeName == numOfName) {
// 日期一样
if (peDate.equals(date))
throw new SameInfoEntryException("第" + (fileLineNum+1) + "行计划项的标签与之前的计划项完全一样");
// 出发和到达机场不全相同
if (!peDeparture.equals(departure) || !peArrival.equals(arrival))
throw new EntryInfoInconsistentException("第" + (fileLineNum+1) + "行计划项同名但起降机场不同");
// 出发和到达时间不全相同
if (!peStart.equals(startStr) || !peEnd.equals(endStr))
throw new EntryInfoInconsistentException("第" + (fileLineNum+1) + "行计划项同名但起降时间不同");
}
判断相同编号的飞机信息是否完全相同:
// 飞机编号相同
if (((FlightEntry<Plane>) pe).getResource().getID().equals(id)
&& !((FlightEntry<Plane>) pe).getResource().equals(plane))
throw new PlaneInfoInconsistentException("第" + (fileLineNum+1) + "行计划项的飞机与之前的同编号飞机信息不一致");
异常处理:在readFileCreatFlightSchedule()方法中调用entries()方法,如果捕获到异常则按如下方式处理,让用户选择是否更换文件,如果是,则再次调用readFileCreatFlightSchedule()方法
catch (InherentFo