The Java Modeling Language (JML) is a specification language for Java programs, using Hoare style pre- and postconditions and invariants, that follows the design by contract paradigm. Specifications are written as Java annotation comments to the source files, which hence can be compiled with any Java compiler.html
jml,簡單來講,就是在每一個方法以前,相似於Javadoc,用註釋的形式寫出這個方法的效果。和其餘規格化是設計不一樣的是,它能夠算是使用了形式化的語言——這樣,咱們就可使用程序來解讀他,同時他也沒有了歧義性。node
他的基礎以下:git
參考:github
https://en.wikipedia.org/wiki/Java_Modeling_Languageweb
《JML Level 0手冊》算法
以上構成了jml的基礎緩存
A variety of tools provide functionality based on JML annotations. The Iowa State JML tools provide an assertion checking compiler
jmlc
which converts JML annotations into runtime assertions, a documentation generatorjmldoc
which produces Javadoc documentation augmented with extra information from JML annotations, and a unit test generatorjmlunit
which generates JUnit test code from JML annotations.bash——https://en.wikipedia.org/wiki/Java_Modeling_Language架構
jml 須要支持一個編譯器jmlc
,一個文檔生成器 jmldoc
,一個單元測試程序jmlunit
如下團隊在作jml相關內容
- ESC/Java2 [1], an extended static checker which uses JML annotations to perform more rigorous static checking than is otherwise possible.
- OpenJML declares itself the successor of ESC/Java2.
- Daikon, a dynamic invariant generator.
- KeY, which provides an open source theorem prover with a JML front-end and an Eclipse plug-in (JML Editing) with support for syntax highlighting of JML.
- Krakatoa, a static verification tool based on the Why verification platform and using the Coq proof assistant.
- JMLEclipse, a plugin for the Eclipse integrated development environment with support for JML syntax and interfaces to various tools that make use of JML annotations.
- Sireum/Kiasan, a symbolic execution based static analyzer which supports JML as a contract language.
- JMLUnit, a tool to generate files for running JUnit tests on JML annotated Java files.
- TACO, an open source program analysis tool that statically checks the compliance of a Java program against its Java Modeling Language specification.
- VerCors verifier
在Github和Gitlib搜索JML,大體得到了一下比較完善的開源項目實現:
這裏嘗試使用了一個較爲簡單的類
(有錯誤)
public class Alu { /*@ @ ensures (a <= b) ==> (\result == a); @ ensures (a > b) ==> (\result == b); @*/ public static int min(int a, int b) { return Integer.min(a, b); } /*@ @ ensures (a >= b) ==> (\result == a); @ ensures (a < b) ==> (\result == b); @*/ public static int max(int a, int b) { return Integer.min(a, b); } }
分別運行
java -jar jmlunitng.jar Alu.java
javac -cp jmlunitng.jar *.java java -jar openjml.jar -rac Alu.java
(注意這裏jmlunitng和openjml都只支持java8)
而後查看生成的文件
. ├── Alu.class ├── Alu.java ├── Alu_ClassStrategy_int.class ├── Alu_ClassStrategy_int.java ├── Alu_InstanceStrategy.class ├── Alu_InstanceStrategy.java ├── Alu_JML_Test.class ├── Alu_JML_Test.java ├── Alu_max__int_a__int_b__0__a.java ├── Alu_max__int_a__int_b__0__b.java ├── Alu_min__int_a__int_b__0__a.class ├── Alu_min__int_a__int_b__0__a.java ├── Alu_min__int_a__int_b__0__b.class ├── Alu_min__int_a__int_b__0__b.java ├── PackageStrategy_int.class ├── PackageStrategy_int.java ├── PackageStrategy_java_lang_String.class ├── PackageStrategy_java_lang_String.java ├── PackageStrategy_java_lang_String1DArray.class └── PackageStrategy_java_lang_String1DArray.java
這裏閱讀這些文件,能夠注意到Jmlunitng生成的單元測試文件是使用TestNG測試的。
所以咱們使用TestNG測試。
獲得如上結果。
能夠看到有的test Failed了,這就說明咱們寫錯了,這時候,就能夠去查找對應的錯誤了。
(仔細查找,能夠發現是我Max裏面返回的是min(故意寫錯的(笑)))
如下是三次做業的橫向對比:
第一次:
第二次:
能夠看到,我前兩次做業的結構比較簡單,基本只是使用簡單的方法實現了題目要求。
每次也是基本複製了前一次代碼。
第三次
第三次做業,我進行較大的改動。
如下是類圖:
首先,我將算法封裝了起來,封裝成了一個ShortestPathAlgorithm類,裏面有靜態的方法,經過傳入圖,進行計算。
而後,我是寫了Calculator抽象類,這個抽象類要負責對圖進行儲存,實時計算最短路,並緩存。
我分別實現了兩種Calculator,分別是Mapped和Normal,其中Mapped是爲了我在拆點的時候,給點編號使用了Map,所以單獨實現了。
以後,我實現了一個工廠類GraphBuilder負責建圖。在建圖的時候,須要傳入一個Engine,這個Engine要負責計算每條邊的長度。(即,不一樣的需求,只須要更改和重寫engine便可)
由此我實現了代碼的服用和解耦。
很不幸,我在第一次做業中寫出了bug,得了60分。
我在維護每一個點點出現的個數這個map的時候,我在若是加入一個已經存在的Path時,我可能重複加入,雖然只是一行代碼的問題,可是這可帶來的巨大的bug。
所以,在以後的實驗中,我吸收了教訓,進行了較多的測試,並寫了自動化的測試。
如下是個人datamaker
https://github.com/login256/BUAAOO-homework11-datamaker
OO的目的是什麼?這是我常常思考的問題。除告終構上的容易理解、好看,我以爲,或許在最初提出的時候,還有一個重要的目的,就是代碼的封裝和複用。
對,代碼複用。仔細想一想以前我每次的設計架構,除了符合面向對象的標準,我考慮的最多的就是:這樣好很差寫,或者說,這樣的代碼會不會寫出大量的冗雜?
在此次OO做業中,我漸漸明白了,人們爲何要提出一個又一個新的設計方法,從面向過程,到面向對象,再到函數式...人們其實就是想讓代碼「好看」、「美妙」。所謂好看,就是美觀,你們容易讀懂,容易配合,所謂美妙,就是簡潔,就是沒有冗雜的代碼。
我也但願自已之後能寫出NB的代碼!
在寫隔壁那門OS課的時候,咱們有時也須要根據每一個函數的註釋的規格(寫了前置條件,後置條件等等),來補全每一個函數。然而,咱們常常碰見這樣一種狀況:這個註釋寫的太模糊了!根本讀不懂!
當時,我就在想,有沒有辦法,讓規格能夠少一些歧義。
終於,在OO這門課中,我學到了JML這門語言!
形式化->能夠準確描述/沒有歧義。
形式化->能夠被程序讀取!
這樣,不只寫代碼的人能夠準確讀懂需求,測試人員還能夠直接根據JML自動生成測試數據!
這是多麼厲害的一件事情啊。
所以,我在此次做業中,明白了什麼叫作實現細節和行爲描述分隔開來,明白了這樣的好處,也明白了形式化的語言的好處。在使用JML工具的時候,我也進行了各類探索感覺到了探索的樂趣!
最後,祝OO這門課愈來愈好,祝計算機學院的學生們獲得更好的鍛鍊!