Use JML to improve your Java program

Source: Internet
Author: User

Java Modeling Language (JML) is a symbolic language for detailed design. It encourages you to look at Java classes and methods in a brand new way. In this tutorial, Joe verzulli, a senior consultant for Java programming, will introduce this new tool and how to use it.

An important principle of Object-Oriented Analysis and Design (OOAD) Is that procedural thinking should be postponed as much as possible, however, most people who follow this principle apply this principle to the method implementation level. Once the class and interface are designed, the following is the method defined in it. Right. What else can we do? Is there any other way to use it? After all, we need to implement every method step by step in the same way as programming in other languages.

The tag itself only indicates how to do something, no matter what we want to do. If we can know what results we can achieve before doing something, however, the Java language does not provide us with a way to explicitly insert this information into our program code.

Java Modeling Language (JML) adds some symbols to Java code. These symbols are used to identify what a method is, but do not care about its implementation. If JML is used, we can describe the expected functions of a method regardless of how it is implemented. In this way, JML delays procedural thinking to the method design, thus extending the object-oriented design principle.

JML introduces a large number of structures used to describe behaviors, such as model domains, quantifiers, asserted visual scopes, preprocessing, post-processing, conditional inheritance, and normal behaviors (relative to abnormal behaviors. These structures make JML very powerful, but you do not need to understand or use all the aspects described above, or use all these aspects at a time. You can start learning at 1.1.

This article introduces JML in a step-by-step manner. First, let's take a look at the advantages of using JML, especially the impact on the development and compilation processes. Then, we will discuss some JML structures, such as preconditions, post conditions, model domains, quantifiers, side effects, and abnormal behaviors. At the same time, while discussing these structures, we will provide some routines to give you an intuitive feeling. After learning this article, you will have a conceptual understanding of how JML works, so that you can apply JML in your own projects.

JML Overview

Declarative use of JML to describe the expected behavior of a method or class can significantly improve the overall development process. Adding modeling tags to your Java code has the following benefits:

More accurately describe what the code is.

Efficiently detects and fixes bugs in programs

It can reduce the chance of introducing bugs during application upgrade.

Early discovery of class errors in Customer Code

Provides documents in JML format that are exactly the same as the application code.

The JML mark is always inside the Java annotation, so it has no impact on the normal compiled code. If you want to compare the differences between common classes and JML classes, you can use an open-source JML Compiler (refer to the following link ). If the Code Compiled with the JML compiler does not meet the requirements of the JML specification, a JML exception will be thrown during runtime. This feature not only helps us capture bugs in code, but also ensures that JML documents are highly consistent with program code.

In the following section, I will use the priorityqueue interface and binaryheap class in the open-source Jakarta commons collection component (jccc) project to demonstrate various JML properties. Here you can find the two files marked completely with JML.

Requirements and responsibilities

The code used in this article (see the following link) includes the priorityqueue interface in the open-source project jccc. The interface naturally declares the signatures of some methods, including the parameter type and Return Value Type of the method, and does not involve the implementation of the method. Generally, the class that implements the interface only needs to implement the methods defined in the interface according to the Java syntax requirements, no matter how strange the implementation method is. We don't want to do this. We hope to be able to determine a behavior specification. All classes that implement this interface use the method we specify to implement the methods defined in this interface. We can do this by using JML.

Consider the POP () method of the priorityqueue interface. What functional requirements should the POP () method have for Priority Queues? There should be at least three elements: first, if you want to call the POP () method, there must be at least one element in the queue; second, the method should return the element with the highest priority in the queue; third, this method should delete the returned element from the queue.

The following code segment shows the JML mark that meets the first requirement:

Code snippet 1 pop () method JML mark of functional specifications

/*@

@ Public normal_behavior

@ Requires! Isempty ();

@*/

Object POP () throws nosuchelementexception;

As mentioned above, the JML mark is written in the Java code comment. Multiline comments containing the JML mark start with/* @, and JML ignores any blank lines starting. If it is a single row, you can also use the // @ flag.

Here, the public keyword in the JML annotation is the same as the public keyword in Java, which indicates that all other classes in the program must comply with this JML requirement. Public must be applied only to public methods and Public member variables. JML also has private-, protected-, and package-level scopes. Similarly, the rules of these scopes are very similar to those of the Java language.

The normal_behavior keyword indicates that this JML requirement indicates that this is a normal situation and will not throw an exception during running. Later, we will describe how abnormal behaviors are defined.

Prerequisites and prerequisites

The JML keyword requires is used to indicate preconditions. Preconditions indicate requirements that must be met before a method is called. The above code snippet contains a precondition that the isempty () method returns false, that is, the queue must contain at least one element.

The post-condition specification of a method indicates the responsibility of a method. That is to say, when the method returns, it must meet the requirements of this post-condition. In our example above, the POP () method should return the element with the highest priority in the queue. We want to specify a post condition that requires JML to check whether this fact is met during runtime. To do this, we must track all elements added to this priority queue so that we can determine which element should be returned by the POP () method. How can this problem be solved? You may consider adding a member variable to the priorityqueue interface to store the values of the elements in the queue. However, there are two problems:

Priorityqueue is an interface that may have different implementation methods, such as binary heap, Fibonacci heap, or calendar queue. It must be consistent with its various implementations, besides, JML labels should not involve any specific implementation details.

As an interface, priorityqueue can only have static member variables.

To handle this situation, JML introduces a concept called model fields.

Model domain

The model field is similar to a member variable and can only be applied to the behavior specification. This is an example of declaring a model field in priorityqueue:

// @ Public model instance jmlobjectbag elementsinqueue;

This statement indicates that there is a model field called elementsinqueue, whose type is jmlobjectbag (this data type is defined in JML ). The instance keyword indicates that although this field is defined in the interface, any class implementing this interface has a separate non-static elementsinqueue field. Like other JML labels, this declaration also appears in comments, so this elementsinqueue variable cannot be used in general Java code. When the program runs, no object has a member variable called elementsinqueue.

Code of Conduct and implementation

Use a package to store the elements in the queue, and then check each element to find the one with the highest priority, which makes people feel inefficient. However, this is only part of the code of conduct, and does not involve implementation. The role of the behavior specification is to describe the behavior interface of priorityqueue, that is, to define the external behavior that the customer code that uses priorityqueue can depend on.

Each specific implementation of the priorityqueue interface can use any more efficient method as long as it meets the requirements of this behavior specification. For example, jccc has a binaryheap class that implements this interface. Its implementation method is to use a binary heap stored in the array.

However, although the execution efficiency does not need to be considered when using JML to define the behavior norms, the JML asserted check is very important when the program is running. Therefore, when you enable the assertion check, the program may run under performance pressure.

Elementsinqueue stores the values of elements added to the priority queue. The following code snippet shows how the POP () method uses elementsinqueue:

Code Segment 2 uses the Model Field in the post condition of POP ()

/*@

@ Public normal_behavior

@ Requires! Isempty ();

@ Ensures

@ Elementsinqueue. Equals (jmlobjectbag)

@/Old (elementsinqueue ))

@. Remove (/result ))&&

@/Result. Equals (/old (PEEK ()));

@*/

Object POP () throws nosuchelementexception;

The ensures keyword indicates the post condition that must be met when the POP () method is returned. /Result is a JML keyword, which is equal to the return value of the POP () method. /Old () is a JML function that returns the value of the parameter before the POP () method is called.

The ensures statement contains two post conditions. First, the element returned by the POP () method must be deleted from elementsinqueue. Second, the returned value must be consistent with the value returned by the peek () method.

Class-level Invariant

Now we can see that JML allows us to specify the pre-and post-conditions of the method, and it also allows us to specify class-level constants. Class-level constants refer to the conditions that each method must meet in and out of a class. For example, // @ public instance invariant elementsinqueue! = NULL is a constant of priorityqueue. It means that the value of elementsinqueue cannot be null once any class implementing priorityqueue is instantiated.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.