-
- Error and Exception Handling
- 处理输入文本中的三类错误
- Error and Exception Handling
DataPatternException
在正则表达式匹配时,若没有匹配到则抛出该错误
if (!matcher.find()) {
try {throw new DataPatternException("mismatch");}
catch(DataPatternException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println("mismatch");///1///
}
EntryNumberFormatException
检查是否符合“前两个字符为大写字母,后2-4个字符为数字
int flag2=0;
if (Character.isUpperCase(planningEntryNumber.charAt(0))
&& Character.isUpperCase(planningEntryNumber.charAt(1))) {
for (int i = 2; i < planningEntryNumber.length(); i++) {
if (!Character.isDigit(planningEntryNumber.charAt(i))) {
try {throw new EntryNumberFormatException(planningEntryNumber + " has incorrect EntryNumberformat.");}
catch(EntryNumberFormatException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println(planningEntryNumber + " has incorrect EntryNumberformat.");}
flag2=1;
}
}
} else {
try {throw new EntryNumberFormatException(planningEntryNumber + " has incorrect EntryNumberformat.");}
catch(EntryNumberFormatException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println(planningEntryNumber + " has incorrect EntryNumberformat.");}
flag2=1;
}
return flag2;
SameAirportException
两个机场字符串是否相等。
TimeOrderException
起飞时间应该在到达时间之前
if(time.getbegin().getMillis()>time.getend().getMillis()) {
try {throw new TimeOrderException(" TimeOrder.");}
catch(TimeOrderException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println( " TimeOrder.");}///4///
PlaneNumberFormatException
飞机编号不符合格式,检查字符串长度以及首字母、后4位数字
int flag5=0;
if(planNumber.length()!=5) {
try {throw new PlaneNumberFormatException(planNumber + " incorrect PlanNumberlenth.");}
catch(PlaneNumberFormatException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println(planNumber + " incorrect PlanNumberlenth.");}
flag5=1;
}
if (planNumber.charAt(0)=='N'||planNumber.charAt(0)=='B') {
for (int i = 1; i < planNumber.length(); i++) {
if (!Character.isDigit(planNumber.charAt(i))) {
try {throw new PlaneNumberFormatException(planNumber + " has incorrect PlanNumberformat.");}
catch(PlaneNumberFormatException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println(planNumber + " has incorrect PlanNumberformat.");}
flag5=1;
}
}
} else {
try {throw new PlaneNumberFormatException(planNumber + " has incorrect PlanNumberformat.");}
catch(PlaneNumberFormatException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println(planNumber + " has incorrect PlanNumberformat.");}
flag5=1;
}
return flag5;
PlaneTypeException
飞机类型不符合格式检查是否由字母和数字构成。
PlaneSeatRangeException
飞机座位数范围错误转换为整数比较范围。
PlaneAgeFormatException
飞机年龄非一位小数或整数,查找小数点的位置,字符串比较,
SameEntryException
存在两个航班,飞机和航班号都相等。
HugeTimeGapException
起飞时间和到达时间超过一天。
EntryInconsistentInfoException
相同航班号的航班信息起降时间不一致。
InconsistentdatesException
航班计划项日期不一致
EntryLocationInfoException
相同航班号的航班信息起降地点不一致。
-
-
- 处理客户端操作时产生的异常
-
DeleteAllocatedResourceException在删除某资源的时候,如果有尚未结束的计划项正在占用该资源
for(ActivityEntry<activityresource> p:actlist) {
if(p.getres().getname().equals(Name)) {
if(!(p.getstate().equals("ENDED"))) {
///System.out.println( "222");
try {throw new DeleteAllocatedResourceException( " DeleteAllocatedResource.");} ///2.1///
catch(DeleteAllocatedResourceException e){System.out.println( " DeleteAllocatedResource.");}
return false;
}
}
}
DeleteOccupiedLocationException
原因:在删除某位置的时候,如果有尚未结束的计划项正在该位置执行
for(ActivityEntry<activityresource> p:actlist) {
if(p.getlocation().getname().equals(loc)) {
if(!(p.getstate().equals("ENDED"))) {
try {throw new DeleteOccupiedLocationException( " DeleteOccupiedLocation.");} ///2.2///
catch(DeleteOccupiedLocationException e){System.out.println( " DeleteOccupiedLocation.");}
return false;
}
}
}
UnableCancelException
在取消某计划项的时候,如果该计划项的当前状态不允许取消
switch (c) {
//返回新状态白
case "cancel":try {throw new UnableCancelException(" UnableCancel.");}
catch(UnableCancelException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println( " UnableCancel.");}///2.3///
ResourceSharedException
在为某计划项分配某资源的时候,如果分配后会导致与已有的其他计划项产生“资源独占冲突”
for(PlaneEntry<planeresource> a:plalist)
{
if((!(a.getstate().equals("WAITING")))&&a.getres().getnumber().equals(resname)) {
if(!(a.getstate().equals("ENDED"))) {
try {throw new ResourceSharedException( " ResourceSharedException.");} ///2.4///
catch(ResourceSharedException e){
logger.log(Level.SEVERE, e.getMessage(), e); //日志
System.out.println( " ResourceSharedException.");}
return;
}
}
}
LocationSharedException
在为某计划项变更位置的时候,如果变更后会导致与已有的其他计划项产生“位置独占冲突”
for(ActivityEntry<activityresource> p:actlist) {
if(p.getlocation().getname().equals(newloc)) {
if(!(p.getstate().equals("ENDED"))) {
try {throw new DeleteOccupiedLocationException( " DeleteOccupiedLocation.");} ///2.5///
catch(DeleteOccupiedLocationException e){System.out.println( " DeleteOccupiedLocation.");}
return ;
}
}
}
-
- Assertion and Defensive Programming
- checkRep()检查rep invariants
- Assertion and Defensive Programming
TimeSlot
/*
* AF:
* begin出发时间,end到达时间
*
*
* RI:
* 不为空 到达晚于出发
*
* Safety:
* private
*/
Location
private void checkRep() {
assert (begin.getMillis()< end.getMillis());
}
// Abstraction function:
// 用经纬度longitude latitude;名称name 共享shareable属性表示地点
// Representation invariant:
// 不为空
// Safety from rep exposure:
// 使用private 防御编程
private void checkRep() {
assert(name!=null);
}
EntryState
/*
* AF:
* the state name represents the state
* RI:
* state must change as required
* Safety:
* it's a mutable object
*/
planeresource
// Abstraction function:
// 编号number型号type人数people年龄age
// Representation invariant:
// 不为空
// Safety from rep exposure:
// 使用private 防御编程
private void checkRep() {
assert (number!=null);
assert (type!=null);
assert (people!=null);
assert (age!=null);
}
Trainresource
// Abstraction function:
// 编号number型号type人数people年龄age
// Representation invariant:
// 不为空
// Safety from rep exposure:
// 使用private 防御编程
private void checkRep() {
assert (number!=null);
assert (type!=null);
assert (people!=null);
assert (age!=null);
}
activityresource
// Abstraction function:
// 名称name部门department日期date数量number
// Representation invariant:
// 不为空,number>0
// Safety from rep exposure:
// 使用private 防御编程
private void checkRep() {
assert (name!=null);
assert (department!=null);
assert (date!=null);
assert (number>0);
}
PlanningEntry
/**
* a factory method for generating an instance of PlaneEntry
* @param <R>
* @return an empty instance of planning entry of PlaneEntry
*/
public static <R> PlaneEntry<R> newPlanningEntryOfPlane() {
return new PlaneEntry<R>();
}
/**
* a factory method for generating an instance of TrainEntry
* @param <R>
* @return an empty instance of planning entry of TrainEntry
*/
public static <R> TrainEntry<R> newPlanningEntryOfTrain() {
return new TrainEntry<R>();
}
/**
* a factory method for generating an instance of ActivityEntry
* @param <R>
* @return an empty instance of planning entry of ActivityEntry
*/
public static <R> ActivityEntry<R> newPlanningEntryOfActivity() {
return new ActivityEntry<R>();
}
/**
* start the planning entry
*/
public void start();
/**
* cancel the planning entry
*/
public void cancel();
/**
* complete the planning entry
*/
public void complete();
/**
* allocate the planning entry state
*/
public void allocate();
-
-
- Assertion/异常机制来保障pre-/post-condition
-
EntryState通过switch限制状态只能合法变换,只有高铁有block的方法
在分配资源时先查询是否存在资源
-
-
- 你的代码的防御式策略概述
-
在客户端输入的时候对其数据进行检查,在adt中再次检查
-
- Logging
- 异常处理的日志功能
- Logging
private final static Logger logger = Logger.getLogger("Flight Schedule Log");{
Locale.setDefault(new Locale("en", "EN"));
logger.setLevel(Level.INFO);
FileHandler fileHandler;
try {
fileHandler = new FileHandler("src/txt/FlightScheduleLog.txt", true);
fileHandler.setFormatter(new SimpleFormatter());
logger.addHandler(fileHandler);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//日志
本实验中,日志功能的实现调用了 Java 的库 java.util.logging。
private final static Logger logger = Logger.getLogger("Flight Schedule Log");
日志配置。
首先配置日志的输出语言为英文。
Locale.setDefault(new Locale("en", "EN"));
然后设置日志显示信息的最低级别(
logger.setLevel(Level.INFO);
加入相应的文件管理,使得日志可以写入到文件中。
FileHandler fileHandler = new FileHandler("log/FlightScheduleLog.txt", true);
fileHandler.setFormatter(new SimpleFormatter());
logger.addHandler(fileHandler);
-
-
- 应用层操作的日志功能
- 日志查询功能
- Testing for Robustness and Correctness
- Testing strategy
-
测试各类异常是否正确触发
-
-
- 测试用例设计
-
文件测试用例在test/txt/
客户端异常测试节选
@Test
public void ResourceSharedExceptiontest2() throws DeleteOccupiedLocationException,Exception {
//exception.expect(DeleteAllocatedResourceException.class);
// exception.expectMessage("xinhua 正在被占用");
FlightScheduleApp app = new FlightScheduleApp();
app.AddLocation("a1");
app.AddLocation("a2");
app.CreatPla("CZ001", "a1", "a2", "2020-01-08 20:48", "2020-01-08 21:48");
app.CreatPla("CZ002", "a1", "a2", "2020-02-08 20:48", "2020-02-08 21:48");
app.CreatRes("2", "A001", "N001", "100");
app.allocateres("CZ001", "N001");
app.allocateres("CZ002", "N001");
//app.StartPlanningEntry("2020-01-08,502");
}
@Test
public void ResourceSharedExceptiontest1() throws DeleteAllocatedResourceException,Exception {
List<trainresource> rs= new ArrayList<trainresource>();
List<Location> ls= new ArrayList<Location>();
List<Timeslot> ts=new ArrayList<Timeslot>();
TrainScheduleApp app = new TrainScheduleApp();
app.AddLocation("a1");
app.AddLocation("a2");
for(Location l:app.loclist)
{
if(l.getname().equals("a1")||l.getname().equals("a2")) {
ls.add(l);
}
}
app.CreatRes("2", "A001", "N001", "100");
app.CreatRes("2", "A001", "N002", "100");
for(trainresource l:app.reslist)
{
if(l.getnumber().equals("N001")||l.getnumber().equals("N002")) {
rs.add(l);
}
}
Timeslot t=new Timeslot("2020-01-08 20:48", "2020-01-08 21:48");
ts.add(t);
app.CreatTra("Z001", ls, ts);
app.CreatTra("Z002", ls, ts);
app.allocateres("Z001", rs);
app.allocateres("Z002", rs);
}
-
-
- 测试运行结果与EclEmma覆盖度报告
-
测试结果在src/txtd的日志中
-
- SpotBugs tool
没有发现错误,在修改的过程中出现过越界问题。
-
- Debugging
- EventManager程序
- Debugging
将区间的每一个整数点进行标记(用Map),查找Map.values()最大值。
通过测试发现空指针异常,没有对对应key值进行判断。判断后进行初始化,每次遇到start对对应value值加1,遇到end对对应value值-1,然后通过有序的遍历,进行最大值的筛选,可以得到一年中的最大k值。最后将日期换算成小时,并进行异常判断。
-
-
- LowestPrice程序
-
在有special offer的情况下最优价格。使用贪心算法。假设最低代价为全用零售,然后每次将一个special offer加入“购物车”,更新,再迭代求解,测试可知如果差值为负数应该直接break并且等于0时可以继续进行,由于特殊价格链表本身就比商品长度多出价格,所以迭代是不用-1最后加入异常判断。
-
-
- FlightClient/Flight/Plane程序
-
通过枚举每个航班,尝试安排飞机,确保没有与其他已经分配的航班冲突,最后确认是否能所有同时分配成功。
字符串的==判断应替换为.equals
根据编译器的静态检查sort并不能直接对List<Flight>使用,改成before()以及after()
经过调试可以发现即使遍历完所有飞机,但无法跳出while循环,所以对随机选择飞机进行修改,调用过的飞机将他排除在下一次随机选择范围外,并计数,达到飞机个数时跳出循环。将bAllocated当做标志变量,在分配完后不使用break跳出循环,而选择更改bAllocated的值为true,若发现bAllocated为false,将bFeasible改为false并返回。