OO第三单元总结——JML规格
一、JML简介
1.JML语言的理论基础
JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言。JML是一种行为接口规格语言 (Behavior Interface Specification Language,BISL),基于Larch方法构建。BISL提供了对方法和类型的规格定义手段。
- 一般而言,JML有两种主要的用法:
(1)开展规格化设计。这样交给代码实现人员的将不是可能带有内在模糊性的自然语言描述,而是逻辑严格的规格。
(2)针对已有的代码实现,书写其对应的规格,从而提高代码的可维护性。这在遗留代码的维护方面具有特别重要的意义
基本语言:
1.注释结构
行注释的表示方式 为 //@annotation ,块注释的方式为 /* @ annotation @*/ 。
2.JML表达式
2.1 原子表达式
\result表达式、\old( expr )表达式、\not_assigned(x,y,...)表达式、\not_modified(x,y,...)表达式、\nonnullelements( container )表达式、\type(type)表达式、\typeof(expr)表达式……
2.2 量化表达式
\forall表达式、\exists表达式、\sum表达式、\product表达式、\max表达式、\min表达式、\num_of表达式……
2.3 集合表达式
集合构造表达式:可以在JML规格中构造一个局部的集合(容器),明确集合中可以包含的元素。
2.4 操作符
(1) 子类型关系操作符: E1<:E2
(2) 等价关系操作符: b_expr1<==>b_expr2
(3) 推理操作符: b_expr1==>b_expr2
(4) 变量引用操作符
3. 方法规格
(1) 前置条件(pre-condition) : requires P; 。
(2) 后置条件(post-condition) : ensures P; 。
(3) 副作用范围限定(side-effects) : assignable 或者 modifiable 。
4. 类型规格
JML针对类型规格定义了多种限制规则,从课程的角度,我们主要涉及两类,不变式限制(invariant)和约束限制 (constraints)。无论哪一种,类型规格都是针对类型中定义的数据成员所定义的限制规则,一旦违反限制规则,就称 相应的状态有错。
2.工具链
JML的一大优势就在于其丰富的外围工具,它们都被罗列在了http://www.eecs.ucf.edu/~leavens/JML//download.shtml上。其中比较重要的几个如下:
- OpenJML:首选的JML相关工具,以提供全面且支持最新Java标准的JML相关支持为目标,能够进行静态规格检查(ESC,Extended Static Cheking)、运行时规格检查(RAC,Runtime Assertion Checking)和形式化验证等一系列功能。OpenJML提供了自带的命令行版本和Eclipse插件版本。
- JML Editing:官方的Eclipse插件,提供了JML规格的代码高亮及代码补全。
- JMLUnitNG:JMLUnit的替代工具,能够根据JML规格自动生成基于测试库TestNG的单元测试集。
- jmldoc:能够通过JML生成javadoc的工具。现已合并入OpenJML中。
JML还有一系列其他工具,但是这些工具大都是从不同角度根据规格进行代码测试的,这些功能已被OpenJML所涵盖。
二、部署SMT Solver进行验证
略(选做)
三、部署JMLUnitNG并针对Graph接口的实现进行测试
JMLUnitNG的部署方法仰仗伦佬。
- 以下是测试结果
[TestNG] Running:
Command line suite Passed: racEnabled()
Passed: constructor MyGraph()
Passed: <<homework.MyGraph@18ef96>>.addPath(null)
Passed: <<homework.MyGraph@ba4d54>>.containsEdge(-2147483648, -2147483648)
Passed: <<homework.MyGraph@de0a01f>>.containsEdge(0, -2147483648)
Passed: <<homework.MyGraph@4c75cab9>>.containsEdge(2147483647, -2147483648)
Passed: <<homework.MyGraph@1ef7fe8e>>.containsEdge(-2147483648, 0)
Passed: <<homework.MyGraph@6f79caec>>.containsEdge(0, 0)
Passed: <<homework.MyGraph@67117f44>>.containsEdge(2147483647, 0)
Passed: <<homework.MyGraph@5d3411d>>.containsEdge(-2147483648, 2147483647)
Passed: <<homework.MyGraph@2471cca7>>.containsEdge(0, 2147483647)
Passed: <<homework.MyGraph@5fe5c6f>>.containsEdge(2147483647, 2147483647)
Passed: <<homework.MyGraph@6979e8cb>>.containsNode(-2147483648)
Passed: <<homework.MyGraph@763d9750>>.containsNode(0)
Passed: <<homework.MyGraph@2be94b0f>>.containsNode(2147483647)
Passed: <<homework.MyGraph@d70c109>>.containsPathId(-2147483648)
Passed: <<homework.MyGraph@17ed40e0>>.containsPathId(0)
Passed: <<homework.MyGraph@50675690>>.containsPathId(2147483647)
Skipped: <<homework.MyGraph@31b7dea0>>.containsPath(null)
Passed: <<homework.MyGraph@3ac42916>>.getDist()
Passed: <<homework.MyGraph@47d384ee>>.getDistinctNodeCount()
Passed: <<homework.MyGraph@2d6a9952>>.getGraph()
Failed: <<homework.MyGraph@22a71081>>.getPathById(-2147483648)
Failed: <<homework.MyGraph@3930015a>>.getPathById(0)
Failed: <<homework.MyGraph@629f0666>>.getPathById(2147483647)
Failed: <<homework.MyGraph@1bc6a36e>>.getPathId(null)
Failed: <<homework.MyGraph@1ff8b8f>>.getShortestPathLength(-2147483648, -2147483648)
Failed: <<homework.MyGraph@387c703b>>.getShortestPathLength(0, -2147483648)
Failed: <<homework.MyGraph@224aed64>>.getShortestPathLength(2147483647, -2147483648)
Failed: <<homework.MyGraph@c39f790>>.getShortestPathLength(-2147483648, 0)
Failed: <<homework.MyGraph@71e7a66b>>.getShortestPathLength(0, 0)
Failed: <<homework.MyGraph@2ac1fdc4>>.getShortestPathLength(2147483647, 0)
Failed: <<homework.MyGraph@5f150435>>.getShortestPathLength(-2147483648, 2147483647)
Failed: <<homework.MyGraph@1c53fd30>>.getShortestPathLength(0, 2147483647)
Failed: <<homework.MyGraph@50cbc42f>>.getShortestPathLength(2147483647, 2147483647)
Passed: <<homework.MyGraph@75412c2f>>.getUpdateDist()
Failed: <<homework.MyGraph@282ba1e>>.isConnected(-2147483648, -2147483648)
Failed: <<homework.MyGraph@13b6d03>>.isConnected(0, -2147483648)
Failed: <<homework.MyGraph@f5f2bb7>>.isConnected(2147483647, -2147483648)
Failed: <<homework.MyGraph@73035e27>>.isConnected(-2147483648, 0)
Failed: <<homework.MyGraph@64c64813>>.isConnected(0, 0)
Failed: <<homework.MyGraph@3ecf72fd>>.isConnected(2147483647, 0)
Failed: <<homework.MyGraph@483bf400>>.isConnected(-2147483648, 2147483647)
Failed: <<homework.MyGraph@21a06946>>.isConnected(0, 2147483647)
Failed: <<homework.MyGraph@77f03bb1>>.isConnected(2147483647, 2147483647)
Failed: <<homework.MyGraph@326de728>>.removePathById(-2147483648)
Failed: <<homework.MyGraph@25618e91>>.removePathById(0)
Failed: <<homework.MyGraph@7a92922>>.removePathById(2147483647)
Failed: <<homework.MyGraph@71f2a7d5>>.removePath(null)
Passed: <<homework.MyGraph@2cfb4a64>>.size() ===============================================
Command line suite
Total tests run: 50, Failures: 26, Skips: 1
=============================================== - 我还按伦佬的流程,实际操作了一遍。菜菜的我需要反复练习……

四、梳理框架设计
第一次作业:
老老实实按照官方提供的接口写的。

第二次作业:(下图是我debug之后的代码框架。与之前的代码相比,框架是相同的,只是部分存储的数据结构不同)
作业框架基本和接口一样。第二次作业主要在MyPathContaineri的基础上增加了几个接口,我没有选择继承,而是直接Ctrl C 、Ctrl V了(捂脸)。

第三次作业:
难度提升,这一次的框架还是按照官方给的接口来写的。不过我将对图的操作以及floyd算法的操作封装成了一个类MyMap类。

这三次作业我的框架是没变的,第二次和第三次我用的都是邻接矩阵初始化距离矩阵,利用floyd算法来求最小权重的路径。不过在第二次作业TLE之后,我发现hashmap在这种算法下远不如静态数据运算快,所以第三次作业是用的静态数组来完成的算法。
五、分析代码实现的bug和修复情况
第一次作业:
这次作业实现难度不大,关键在于复杂度的控制。在这次作业中,我利用了已有的容器(如 hashmap 、hashset等)来减少我自己写的代码量。当初想着,这些已经有的容器的算法肯定比我写得强多了,却没真正深入探究容器自身实现的复杂度。
Mypath类中,当需要getDistinctNodeCount时,我都会new一个hashset来统计。这对path这个类来说,确实是比较简单且复杂度低的方法。
但是我在MyPathContainer 类里偷懒,依然用的是这个方法。然而MyPathContainer类里会频繁地add和remove,导致每当getDistinctNodeCount时,我都会重头统计,复杂度是O(n)。这一问题让我在强测中TLE了。
bug修复时,我通过增加一个HashMap存储当前某个节点出现了多少次,将复杂度分散到add和remove操作中,getDistinctNodeCount时只需输出当前hashmap的size即可,复杂度降到了O(1)。
第二次作业:
对于第二次作业新增的方法,我运用的是Floyd算法来完成的。考虑到add和remove的指令占比很小,选择Floyd算法是非常合适的,第二、三作业的结果也证实了这一点。
不过这次我还是TLE了,我入了hashmap的坑。我本想,第二次作业是个稀疏矩阵,用hashmap存储会更节俭一点。却万万没想到,在有下标索引的情况下,静态数组查询、更新等的实现速度是远远快于hashmap 的。从此,我对hashmap的蜜汁好感产生了动摇……
第三次作业:
这一次作业我机智地没有选择拆点法(听说拆点法很难写而且运行时间太久……)
我选择了另一种主流思想,每一条Path连成一个完全图存入MyMap中。当初做抉择的时候,考虑到拆点法是在删增Path的时候需与图中几乎全部的信息比对来动态改变每个节点的个数,而完全图的方法的任何一个操作都是对一个Path独立的(加是加一个完全图,删是删一个完全图),并不需要与其他Path进行比较。基于这一点,我觉得完全图这种简单的构图方式比较适合我。
我估计是对TLE产生了心里阴影,这次我是在我能力范围内尽可能地优化复杂度,结果把自己给优化死了……这次求最少换乘次数、最短路径(最少票价)、最小不满意度,都是同一张图,但是赋三种权值。
由算法的实现可知,每条边的权值都要是这条边在它所属的所有path中权值最小的。我为每条边存储了一个他所属的Path的id和在这个Path中它的权值的栈。add和remove的时候,给距离矩阵初始化的时候,就会从每个边的栈中找到最小的权值给它附上。可是我在我这些优化的时候,因为一些笔误导致我更新遗漏,强测wa了。
六、对规格撰写和理解上的心得体会
感觉规格专业很像离散数学中的谓词逻辑,所以理解起来并不是很难。
主要的体会是:
规格只是对结果的描述,却没有限定实现的具体方法;
规格定义中只能调用pure方法,描述的是状态而非动态过程。
OO第三单元总结——JML规格的更多相关文章
- OO第三单元总结——JML规格设计
• 1.JML语言的理论基础.应用工具链情况 JML(Java Modeling Language)—— java建模语言,是一种行为接口规范语言( behavioral interface spec ...
- 2019年北航OO第三单元(JML规格任务)总结
一.JML简介 1.1 JML与契约式设计 说起JML,就不得不提到契约式设计(Design by Contract).这种设计模式的始祖是1986年的Eiffel语言.它是一种限定了软件中每个元素所 ...
- OO第三单元——基于JML的社交网络总结
OO第三单元--基于JML的社交网络总结 一.JML知识梳理 1)JML的语言基础以及基本语法 JML是用于java程序进行规格化设计的一种表示语言,是一种行为接口规格语言.其为严格的程序设计提供了一 ...
- OO第三单元作业(JML)总结
OO第三单元作业(JML)总结 目录 OO第三单元作业(JML)总结 JML语言知识梳理 使用jml的目的 jml注释结构 jml表达式 方法规格 类型规格 SMT Solver 部署JMLUnitN ...
- 2020 OO 第三单元总结 JML语言
title: 2020 OO 第三单元总结 date: 2020-05-21 10:10:06 tags: OO categories: 学习 第三单元终于结束了,这是我目前为止最惨的一单元,第十次作 ...
- OO第三单元总结——JML
目录 写在前面 JML理论基础 JML工具链 JMLUnitNG的使用 架构设计 Bug分析 心得体会 写在前面 OO的第三单元学习结束了,本单元我们学习了如何使用JML语言来对我们的程序进行规格化设 ...
- OO第三单元(地铁,JML)单元总结
OO第三单元(地铁,JML)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉并了解JML来是我们具有规格化编程架构的思想.这个单元的主题一开始并不明了,从第一次作业的路径到第二次 ...
- OO第三单元作业——魔教规格
OO第三单元作业--魔教规格 JML的理论基础和相关工具 JML(Java Modeling Language,Java建模语言),在Java代码种增加了一些符号,这些符号用来标志一个方法是干什么 ...
- OO第三单元——JML规格化设计
OO第三单元--JML规格化设计 JML语言的理论基础以及应用工具链情况 理论基础 JML是对JAVA程序进行规格化设计的一种表示语言,是一种行为接口规格语言.JML整合了Java和JAVAdoc,并 ...
随机推荐
- 归并排序(JAVA语言)
public class merge { public static void main(String[] args) { // TODO Auto-generated method stub int ...
- 【数据库】Redis(2)--Redis的常用数据类型及命令
1.Redis主要数据类型分类 Redis中存储数据常用的数据类型主要有五种:String.List.Set.Sorted Set.Hash,这五种数据结构在Redis中存储数据的命令掌握对于我们后期 ...
- Jaeger Client Go 链路追踪|入门详解
目录 从何说起 Jaeger 部署 Jaeger 从示例了解 Jaeger Client Go 了解 trace.span tracer 配置 Sampler 配置 Reporter 配置 分布式系统 ...
- SpringBoot-08 SpringSecurity
SpringBoot-08 SpringSecurity 创建了一个新项目,创建时选择导入starter-web 1.环境搭建 1.1 导入thymeleaf <dependency> & ...
- 用pyqt5做一个简易的音乐播放器
需求 要求可以读取音频文档,有播放和暂停的功能 附上代码(1)UI界面 # -*- coding: utf-8 -*- # Form implementation generated from rea ...
- 全网最详细的Linux命令系列-mkdir命令
Linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前目录中具有写权限,并且指定的目录名不能是当前目录中已有的目录. 命令格式: mkdir [选项] 目录... 命令功能: ...
- OO_Unit2 关于性能优化与测试的那些事
OO_Unit2 关于性能优化与测试的那些事 OO的第2单元到本周也就正式完结了.尽管这个单元的主旋律是多线程,但"面向对象"的基本思想仍然是我们一切架构与优化的出发点与前提.因此 ...
- OO_Unit1总结
OO的第一单元作业告一段落,这周是总结而不是码代码,甚至心中有点落空感.OO课给我的一周构建了一个完整的循环,从周二的作业发布到接下来几天的思考和构建程序,再到面向中测进行一部分的bug修复,最后到互 ...
- BUAA_2021_SE_Case_Analysis
案例分析作业 项目 内容 这个作业属于哪个课程 2021春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 案例分析作业 我在这个课程的目标是 通过课程学习,完成第一个可以称之为"软 ...
- 使用CSS3中Canvas 实现两张图片合成一张图片【常用于合成二维码图片】
CSS3 Canvas 实现两张图片合成一张图片 需求 需求:在项目中遇到将一张固定图片和一张二维码图片合成一张新图片,并且用户能够将图片保存下载到本地. 思路:使用 CSS3 中的 Canvas 将 ...