简要写一下lab4的思路。(如果不对的话欢迎各位的建议)
3.1. Error and Exception Handling
首先看到注释2可知,我们检查所读入的文件,如果发现文件中的信息和指导书描述的信息不符合的话,那么==我们不仅要抛出异常、而且要捕获异常并进行异常处理。==参考Piazza老师的回答,当我们发现文件中有异常时,应该立即退出,并提示用户选择其他的的文件进行读取。
3.1.1 文件中的格式错误
我检查了所有可能出现的错误,检查的思路是:一行一行的读取,判断每一行的格式是否均符合lab3给的格式要求。
思路:由lab3可知,去除空行后,文件中每13行表示一个航班计划项,每一行都要符合lab3给出的格式要求。我使用13个正则表达式进行匹配,第一个正则表达式匹配第一行,如果第一行格式错误,直接抛出异常和提示信息,提醒用户换另一个文件进行读取。如果第一行格式正确,则使用第二个正则表达式匹配第一行和第二行,如果不匹配,那么肯定是第二行格式错误,因为我们已经知道第一行格式正确。依次类推,那么就需要13个正则表达式进行匹配。
为啥匹配的时候不是一次匹配一行呢:因为一次匹配一行,可能会出现这样的情况:13行的每一行的信息都是符合格式要求的,但是每一行的顺序不是正确的,这种情况下每次匹配一行也能匹配到相应的信息,但是这显然不符合格式要求。
所有的错误:
①格式不符合Flight:xxx,xxx
②航班日期格式不符合xxxx-xx-xx
③ 航班号不符合格式要求,不是由两位大写字母和 2-4 位数字构成
第二行:
①第二行不是‘{’
第三行:
①格式不符合DepartureAirport:xxx,比如DepartureAirport拼写错误
第四行:
①格式不符合ArrivalAirport:xxx,比如DepartureAirport拼写错误
第五行:
①格式不符合DepatureTime:xxxx,比如DepatureTime 拼写错误
②出发时间格式不符合xxxx-xx-xx yy:yy
第六行:
①格式不符合ArrivalTime:xxx,比如ArrivalTime拼写错误
②到达时间格式不符合xxxx-xx-xx yy:yy
第七行:
①不符合Plane:xxx格式,比如Plane拼写错误
②飞机编号格式不符合要求,不符合第一位为 N 或 B,后面是四位数字
第八行:
①第八行不是‘{’
第九行:
①第九行格式不符合Type:xxx,比如Type拼写错误
②机型格式错误,不符合大小写字母或数字构成,不含有空格和其他符号
第十行:
①第十行不符合Seats:xxx,比如Seats拼写错误
②座位数不是整数
③座位数不在[50,600]
第十一行:
①第十一行格式不符合Age:xxx,比如Age拼写错误
②机龄不符合要求,比如范围不在[0,30],小数位数超过1位
第十二行:
①第十二行不是‘{’
第十三行:
①第十三行不是‘{’
注释:我判断文件是否合法均是按照以上的标号顺序进行判断。(详细见代码)
给所有可能发生的异常实现一个自己的异常类,实现方法就是简单的继承Exception类,然后可以声明一个带参数的构造器方法。考虑到,文件中语法错误的异常很多,所有我将这些异常类统一看为文件格式不合法的异常。
如果文件语句格式不合法,立即抛出异常,像老师所说,出现异常应该终止文件的读取,那么在catch语句中,我也是直接抛出一个异常,在App类里面捕获这个异常就可以使用日志记录这个异常信息,并且提示用户重新选择文件进行读取。
这是App类捕获异常的处理信息。
3.1.2 输入文件中存在标签完全一样的元素
比如:存在多个航班计划项的“日期,航班号”信息完全一样。
思路:读取一个航班项之后,遍历之前已经读取到的航班集,判断是否存在和这个航班项完全相同的航班即可。
详细见代码
自定义的异常类:sameLabelException
3.1.3 输入文件中各元素之间的依赖关系不正确
思路:每次读取了一个航班项之后,就遍历已经读取的航班项,判断是否存在上述依赖关系不正确。详细见代码
自定义的异常类:wrongDependenceException类
部分代码示例
3.1.2 自定义的异常类
以cancelPlanningEntryException异常为例,主要就是继承Exception类就行
具体思路:客户端收到用户指令之后,然后调用相应的方法,如果出现异常,则相应的方法直接抛出相应的异常,客户端直接捕获异常之后就可以返回给用户提示信息。
3.2 Assertion and Defensive Programming
断言和防御式编程:主要是写 rep invariants (RI)、Abstraction Function (AF),以及它们的每个方法的
spec(pre-condition 和 post-condition)。以及checkRep方法。
checkRep方法:
Location类:name != null
Timeslot类:time1 晚于time2 且不为空
Resource类:resource != null
FlightEntry:起飞时间必须要早于降落时间,起飞和降落的机场不相同
CourseEntry:上课时间晚于下课时间。位置不为空。
TrainEntry:所有的中途站不重复,所有的时间对按照时间增序,使用的车厢编号均不相同(将高铁
车次使用的
所有车厢编号放进set类里面,如果set集合的大小等于车厢的数量的大小,则车厢编号均不相同,
否则有重复)。
3.3. Logging
日志记录的信息有:
思路:
** 自己声明一个日志类logRecord,每一个日志类对象表示一条日志信息,日志类的属性有:异常发生的类名、方法名、时间、具体信息、日志等级、异常类型。**
然后声明一个日志管理类logKeeper,管理所有的日志信息,比如可以按照时间或者异常类型等等进行日志的查询。我们把App的日志信息输出到一个文件中,日志管理类logKeeper就可以读取文件信息创建多个日志类对象当客户端需要查询日志时,可以按照自己的格式来反馈给用户。
当出现异常时,需要记录异常的出现的类名、方法名、时间、提示信息、异常类、日志等级。
我设定了两种日志查询的功能,一个是根据时间范围进行日志查询,另一个是根据日志类型来进行日志查询
3.4. Testing for Robustness and Correctness
即测试所有的类。要考虑语句覆盖度、分支覆盖度和路径覆盖度。
分支覆盖度
路径覆盖度
语句覆盖度
3.5. Using SpotBugs tool
① 一开始粘贴3.6节老师给的debug代码的时候, 出现的bug是判断相等用的是==,而不是equals方法
3.6. Debugging
3.6.1 EventManager程序
功能:给定许多个事件的起止时间,需要找出某一时刻同时进行的事件的最大数量。
思路:属性是类型为TreeMap的变量temp,temp的键存储的是事件在时间轴上的时间,值对应的是在该时间点上面同时发生的时间数量的最大值。所以只需要循环temp的所有的值,找出最大的值即可。
使用TreeMap的好处:TreeMap已经是按照键的大小排序,所以可以直接遍历temp,表示从时间轴向后遍历所有的事件,而不需要对键重新进行排序。**
3.6.2 LowestPrice程序
程序功能:给定一组优惠,并且给出我们所需要的各个物品的数量,找出需要购买这些物品的最低价格。
程序思想:首先求出按照商品的单价直接购买商品所需要的价格res。然后,遍历所有的优惠,如果这个优惠的需要的商品的数量不超过我们需要的数量,则递归的求出使用优惠所需要的价格。最低价格就是res和使用优惠的最小值。
3.6.3 FlightClient/Flight/Plane程序
功能:给定一组航班和一组飞机,问能否在飞机不冲突的情况下给每个航班都安排一架飞机。
思路:首先,对航班按照出发时间进行排序,然后随机选取一架飞机,判断如果给这个航班安排飞机是否存在冲突,如果存在冲突选取别的飞机,遍历所有的飞机如果仍然不能安排飞机,则返回false。