JML规格编程系列——OO Unit3分析和总结
本文是BUAA OO课程Unit3在课程讲授、三次作业完成、自测和互测时发现的问题,以及倾听别人的思路分享所引起个人的一些思考的总结性博客。主要包含JML相关梳理、SMT Solver验证、JML单元测试、设计策略、代码度量、BUG测试和心得体会等内容。
目录
一、JML简单梳理
1.1 JML语言理论基础
The Java Modeling Language (JML) is a behavioral interface specification language that can be used to specify the behavior of Java modules. It combines the design by contract approach of Eiffel and the model-based specification approach of the Larch family of interface specification languages, with some elements of the refinement calculus.
JML(Java建模语言)是一种进行详细设计的符号语言,它鼓励我们用一种全新的方式看待Java的类和方法。面对对象的分析和设计的一个终于原则就是过程性的思考应该尽可能地推迟。Java建模语言在Java代码中增加了一些符号,这些符号用来标识一个方法是干什么的,却不关心它的实现。通过这种方式,JML把过程性的思考延迟到了方法设计中,从而拓展了面对对象的这个原则,同时通过引入大量用于描述行为的结构,比如有模型域、量词、断言可视范围、预处理、后处理、正常行为与异常行为等等,这些结构就使得JML非常强大了。通过分析JML,我们能够更为精确地了解代码的用途,减小引入bug的几率,更高效地检测并纠正代码的bug等。
1.2 JML应用工具链
除了OpenJML、JML Editing、JMLUnitNG以外,常用的JML工具还包括以下:
- The AspectJML tool is able to specify and do runtime assertion checking for both Java and AspectJ programs. Ajmlc uses aspect-oriented compilation techniques to provide significantly improved runtime assertion violation messages, and also works with JavaME.
- The jml4c tool is a JML compiler built on the Eclipse Java compiler. It translates a significant subset of JML specifications into runtime checks. Notable features of JML4c include (1) support for Java 5 features such as generics and enhanced
forloops, (2) support for nested classes, (3) improved compilation speed, and (4) improved error messages. Using JML4c, one can now verify Java 5 classes annotated with JML specifications. - Sireum/Kiasan for Java, which is a JML contract-based automatic verification and test case generation tool-set for Java program units.
- JMLEclipse, which is a pre-alpha version of the JML tool-suite developed on top of Eclipse's JDT compiler infrastructure.
- JMLOK is a tool that uses random tests to check Java code against JML specifications and suggest likely causes for non-conformance problems it finds.
二、SMT Solver的部署和验证
因OpenJML不能支持\forall、\exists,本次作业中无法完成测试验证,略。
三、JML单元测试
为了规避\forall和\exists,作业中的其他方法过于简单,改为使用以下测试代码进行测试:
package test;
public class Test extends Exception{
public static void main(String[] args) {
try {
divide(35, 7);
} catch (Exception e) {}
}
/*@ public normal_behavior
@ requires b != 0;
@ ensures \result == a / b;
@ also
@ public exceptional_behavior
@ requires b == 0;
@ signals (Exception e);
@*/
public static int divide(int a, int b) throws Exception {
if (b == 0) {
throw new Exception("Divided by zero!");
} else {
return a / b;
}
}
}
即一个简单的除法(整除),要求除数为零时报错,否则需要输出正确的答案。
测试的结果如下:

可见自动构造的测试数据是使用0,最大正数和最大负数等几个极端数据生成的,这一定程度的和易出现bug的情况相符。
四、架构设计梳理
4.1 第一次作业
4.1.1 类图

4.1.2 简析
第一次作业较为简单,从互测来看同学们的实现也较为类似,基本上按照规格实现功能不需要做很大的改动,选择合适的容器即可完成任务。即对于Path,使用ArrayList即可;对于PathContainer,我采用了双ArrayList,现在来看,实际上使用双HashMap在编写时更直观清晰一些。
4.2 第二次作业
4.2.1 类图

4.2.2 简析
本次作业继承了PathContainer,在保持其原有功能的同时增加了两点间的距离计算,此为本次核心任务。大致有两种不同的设计理念,其一是在add Path和remove Path时使用Dijstra、Floyd等算法计算并缓存所有点之间的距离等信息,可以使查询在瞬间完成,另一种是在查询时才使用DFS等算法来计算距离,则对图结构影响的操作执行起来更快。我采取的是前者,主要在影响图结构的操作执行时更新所有路径容器、距离矩阵、自环统计这三个容器。在修复的时候,为了提升性能,我映入了映射机制,将输入的结点映射到1到250并改用静态数组。因此,除了增加映射机制从而改变了Path的容器和添加、删除方法之外,其他方面基本上无需对上一次的代码进行重构,而增加新功能。
4.3 第三次作业
4.3.1 类图

4.3.2 简析
本次作业继承了Graph,在保持其原有功能的同时增加了更多的要求,基本上都可理解为带权路径的相关最小路径求解,以及需要求联通块数。仍然存在刚才提到的两种设计理念。我仍然使用在图的结构改变时计算所有结果的理念,并继续使用了映射机制。本次对最小路径、最少换乘、最少费用、最低不满意度的计算,实际上是拥有相似性的,都可以通过单程最近距离+换乘两步使用两次Floyd算法完成,因此我将上一次的代码重构为工厂模式,将进行某种特定距离的矩阵的运算封装成产品。联通块数目则单独使用一种算法,由于距离矩阵已经被计算,也可以非常简单地算出。
五、测试与BUG分析
5.1 第一次作业
本次作业中强测出现了超时的问题,但功能是正确的,原因在于代码设计不够合理。原先采用的设计是每次调用计算distinct nodes把所有点加入HashSet重新计算一遍,这是没有必要的,应该直接设置一个HashSet容器来存储所有distinct nodes,并改成每次加入或删除Path时就更新一次该容器,则查询时不再需要重新计算,从而节约CPU运行时间。
本次作业的互测中没有发现bug。
5.2 第二次作业
本次作业中强测也出现了超时的问题,但功能是正确的,原因在于使用的算法不够合理。使用的是一种添桥式的动态规划算法,但由于是每增加一条边更新一次,效率实在太慢,因为增加一条路径时可能有很多条边,而标准的Floyd算法只需要在添加后更新一次即可,就节约了CPU时间,从而不会超时。
由于超时严重,在本次作业的互测分组中发现了较多的bug,主要有使用了错误的算法、容器选择不合理等。主要根据测试的限制构造几乎达到上限的随机数据进行测试即可测出主要的bug。
5.3 第三次作业
本次作业的强测中没有出现bug,互测时也没有找到别人的bug。
六、心得体会
本单元的学习中,我感到规格的特点和好处,尤其在大型项目中,规格是顶层的设计对底层实现的一种很好的规范和约束,免去了思考具体实现,却又能保证正确性。不仅如此,规格能够清晰界定每个模块的功能,这非常有利于高内聚低耦合化的开发。结合单元测试,规格能使程序具有更好的健壮性和可维护性,规格和文档相结合对团队的合作也有较好的帮助。
我感到撰写规格的时候和写程序时既有相似又有不同之处。相似之处在于写规格时也用到了很多相似度很高的语句,而最大不同之处在于规格的目的并不是分析问题解决问题,而是描述某一事物的所有可能性和状态。如正常情况、异常情况,何种条件下会导致怎么样的结果,对哪些数据有影响,哪些数据没有改变。如果想要准确的描述,还应保证语句的规范,例如对数理逻辑中全称量词和存在量词的使用,才能使规格达到要求。为了能使用OpenJML编写时还应注意一些语法格式,由于这方面工具的不充分(没有自动补全、高亮、纠错等),需要格外注意。
本单元中运用的数据结构技巧也很多,我认为最为精巧的设计方法是第三次作业中将票价、最少换乘、最低不满意度、最近距离问题全部转化为单程最近距离+换乘两步使用两次Floyd算法,仅仅有细节上的差异,因此可以使用工厂模式来进行求值,从而使所有查询都能在极短时间内完成。
JML规格编程系列——OO Unit3分析和总结的更多相关文章
- UML系列——OO Unit4分析和学期总结
一.本单元的架构设计 1.类图 第一次 第二次 2.关键方法和架构简述 总体而言是读取图的时候就完成大部分计算(完成缓存),调用查询方法时只是展示计算的结果,少部分直接计算.主要是设计了各种自己定义的 ...
- 电梯系列——OO Unit2分析和总结
一.摘要 本文是BUAA OO课程Unit2在课程讲授.三次作业完成.自测和互测时发现的问题,以及倾听别人的思路分享所引起个人的一些思考的总结性博客.主要包含设计策略.代码度量.BUG测试和心得体会等 ...
- 多项式求导系列——OO Unit1分析和总结
一.摘要 本文是BUAA OO课程Unit1在课程讲授.三次作业完成.自测和互测时发现的问题,以及倾听别人的思路分享所引起个人的一些思考的总结性博客.本文第二部分介绍三次作业的设计思路,主要以类图的形 ...
- 2019年北航OO第三单元(JML规格任务)总结
一.JML简介 1.1 JML与契约式设计 说起JML,就不得不提到契约式设计(Design by Contract).这种设计模式的始祖是1986年的Eiffel语言.它是一种限定了软件中每个元素所 ...
- OO第三单元总结——JML规格设计
• 1.JML语言的理论基础.应用工具链情况 JML(Java Modeling Language)—— java建模语言,是一种行为接口规范语言( behavioral interface spec ...
- OO第三单元总结——JML规格
一.JML简介 1.JML语言的理论基础 JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言.JML是一种行为接口规格语言 (Behavior In ...
- OO Unit3 总结
OO Unit3 总结 OO课Unit3人际关系网JML应用技术回顾 BUAA.1823.邓新宇 2020/5/23 梳理JML语言的理论基础.应用工具链情况 方法规格 JML中,同一个方法在不同的条 ...
- OO unit3 summary
Unit3 JML(Java Modeling Language) 是用于对 Java 程序进行规格化设计的一种表示语言,它对于方法内部具体是如何实现的并无要求,只是对方法的接口以及行为进行限制, ...
- 猫哥网络编程系列:HTTP PEM 万能调试法
注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...
随机推荐
- 软件工程第二次作业——Java学习路线
我的第二次软工作业 过去我对自己所学和想学都很迷茫,以至于学得总是一知半解,但现在我想主攻Java方向,并坚定不移地走下去(之后拓展其他方面就是以后的事情了).之所以想主攻Java方向是因为Java本 ...
- 启动服务器 SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener
意思是spring.jar这个包在发布的时候没有被放入war.如果是maven管理的项目,可以看看这个项目的部署参数里有没有加入所有maven的包. 右键项目->Properties->D ...
- 第06组 Beta版本演示
队名:福大帮 组长博客链接: https://www.cnblogs.com/mhq-mhq/p/12052263.html 作业博客 : https://edu.cnblogs.com/campus ...
- 环境变量path的值大于1024的解决办法
原文传送门:https://blog.csdn.net/jytxj111/article/details/43916421 1.打开Path,点击默认文本(WIN 10),将所有路径备份下来 2.新建 ...
- Android近场通信---NFC基础转)
Android近场通信---NFC基础(一)(转) 本文介绍在Android系通过你所能执行的基本任务。它解释了如何用NDEF消息格式来发送和接收NFC数据,并且介绍了支持这些功能的Android框架 ...
- Eclipse导入工程提示“No projects are found to import”
如果发现导入工程的时候,出现"No projects are found to import" 的提示,首先查看项目目录中是否有隐藏文件.project,还有目录结构也还要有一个隐 ...
- 搭建Bitcoin全节点
节点搭建 1. 进入 bitcoin 选择 Choose your wallet 2. 选择 Bitcoin Core for Linux 下载 bitcoin-0.17.0.1-x86_64-lin ...
- 关于idea跳过错误编译的理解, 跳过报错的代码启动项目去debug测试其他正常的代码
关于idea跳过错误编译的理解 2018年07月13日 19:06:32 weixin_39669410 阅读数 1296 其实idea使用eclipse编译器可以实现跳过报错的代码启动项目去de ...
- 这42个Python小例子,太走心
告别枯燥,60秒学会一个Python小例子.奔着此出发点,我在过去1个月,将平时经常使用的代码段换为小例子,分享出来后受到大家的喜欢. 一.基本操作 1 链式比较 i = 3print(1 < ...
- php读写xml基于DOMDocument方法
1.读xml内容: xml文件plays.xml文档结构: <?xml version="1.0" encoding="UTF-8"?> <P ...