OO第三单元博客

一、JML的语言基础、应用工具链的情况

 

1.1JML理论基础

  JML是对JAVA程序进行规格化设计的一种表示语言。可以用来开展规格化的设计,也可以针对已有的代码写出其规格,从而方便进行维护和提高可读性。

  在我看来JML更像是离散数学中的数理逻辑,满足一定的条件就会推出想要的结果,也显示出一种契约式编程的思想。

JML知识点

  规格的情况分为两种:正常情况、异常情况

  正常情况:public_normal_behavior

  异常情况:public_exceptional_behavior

  require:前置条件,即调用该方法时参数或者变量需要满足的前提条件

  assignable:副作用,列出方法会修改的变量

  ensure:后置条件,方法调用之后参数和成员需要满足的要求

  \result:方法执行之后获得的结果

  \old():方法执行之前对象的取值

  \forall():全称量词,任意

  \exists():存在量词,存在

  invariant:不变式,方法使用的所有的数据都应该满足不变式中的约束条件

  constraint:状态化约束,变化的时候,应当满足状态变化约束所规定的条件

  signals():满足条件就会抛出异常

  \sum:累加求和

  \max:求最大

  \min:求最小

1.2JML应用工具链

  OpenJML:检查JML的规范性

  JMLUnitNG:根据JML语言自动生成数据检测

 

二、部署JMLUnitNG/JMLUnit并使用

  在使用JMLUnitNG的时候,发现其主要测试极端数据,而且经常会报错,更多测试的是边界的条件(感觉不是那么好用与高效)

 

三、作业分析

 

3.1第九次作业

  本来觉得第一次规格的作业很简单,写的很快也不会出现什么问题,结果强测gg,只得了5分。后来看群里助教说可能是islinked没有判断自己和自己的关系,但发现那并不是我的bug……公布强测数据之后才发现是自己在一个方法中的if-else条件的判断出现问题,第一次按照规格写代码,错以为assignab nothing就什么也不用管,没有多加处理,导致方法在不应该抛出异常的时候抛出了异常,强测凄惨。第一次规格作业的收获:要认真阅读规格的要求!

 

3.2第十次作业

  吸取了第九次作业的教训,在写第十次的时候认真阅读了规格,自以为这次不会出现什么问题,但是交上去之后全是超时,又没有进入互测……这次作业出现许多超时的主要原因就是老师后来上课的时候提到的错误,不应该机械地对照着规格去写代码,规格仅仅定义了一种实现的前提和结果要求,实现的过程和其中的具体方法应该自己去思考,自己应该考虑怎么去提高效率、怎么去优化。交上去的强测代码仅仅使用arraylist,并且在很多方法的实现上,草率地选择了规格上写的双重循环,导致强测爆炸。在bug修复的时候,通过自己查阅资料和讨论区的学习,发现hashset、hashmap这种容器的妥善使用会节约很多的时间开销,于是我选择在查询的时候使用hashmap,在遍历的时候使用arraylist。并且在计算relationsum和valuesum的时候,按照大佬的方法,采取了缓存的策略,在加入人的时候进行修改一个存储relationsum的临时变量,达到避免双重循环的目的,最后解决了超时的问题。

 

3.3第十一次作业

  第十次作业主要的难点是stringlink,经过查看离散数学的定义之后,发现如果能够找到一条路径,并且除了起点和终点之外去掉任何路径上的一个点,仍然可以到达,那么就是双连通。之后我就按照这个思路,bfs查找路径,比较巧妙的是,在bfs查找路径的方法中,在把结点加入队列的时候,同时按照<当前节点,父节点>这样的格式加入到hashmap中,就可以达到存储路径的作用,应该是bfs最简单的存路径的方法了,而且很节约时间。查找minpath的时候,经过看讨论区的贴子,学到了堆优化的迪杰斯特拉算法可以提高时间效率,就学习了java的priorityqueue实现了堆优化的迪杰斯特拉算法,在进行单元测试的时候也没有发现什么错误。但是……强测还是出现了问题,问题出在了那个没有写规格的delPerson方法上,我复制粘贴了之前addperson的方法,但是最后的一个判断条件应该加上一个!的逻辑,我忘记更改了……导致强测只得75分,得到的经验教训是测试还是要全面,数据应该覆盖面广一点,没有规格说明的方法更要认真考虑。

 

四、心得体会

  

  通过第三单元的学习,感受到了逻辑语言更容易传递一些信息,而且能够减少二义性,便于理解。也明白了实现程序的时候不应该仅仅面对JML的规格照搬照抄,应该自己考虑一些高效的方法,规格仅仅是为了传递一些说明,自己不应该被束缚。在找bug的时候,感受到了测试的重要性,无论是边界条件还是测试数据的覆盖范围都要考虑到,不然很可能千里之堤溃于蚁穴的结果发生。总体上讲,第三单元的作业看起来很简单,但是真正实现之后,强测的结果并不是很好,在完成作业的时候不应该麻痹大意,更要细心认真才可以。实现方法上,第二次的作业也让我深刻体会到不同容器的选择对最后实现的巨大影响,本单元的学习过程中虽然主要是规格的学习,但还是向很多大佬在思维、算法上有了很多的学习,比如tarjan算法,本单元的这种契约式编程的思想让我受益匪浅。

posted @ 2020-05-23 16:12  whitering  阅读(117)  评论(0编辑  收藏  举报