Agile Javaв„ў: Crafting Code with Test-Driven Development

It is never a good idea to embed literals directly in code, as mentioned earlier. Declaring a local variable as final, which prevents other code from reassigning its value, is a good idea. The final keyword tells other developers that "I don't intend for you to be able to change the value of this variable."

Idiosyncracies: The Final Keyword

You can mark local object and primitive variables as final:

public void testCreate() { final String firstStudentName = "Jane Doe"; final Student firstStudent = new Student(firstStudentName);

You can also mark arguments as final:

Student(final String name) { this.name = name; }

Doing so can provide you with an additional level of protection from other code in the method that assigns a different value to the local variable or argument. Many developers insist on doing so, and it's not a bad practice.

I choose not to, but I recommend that you try it and see how it helps you. My general reason to mark fields as final is for readability, not protection. As a rule, you should never assign values to arguments. And you should rarely reassign values to local object reference variables. I follow both of these rules and don't feel the need to demonstrate that fact by marking the field as final. Instead, I use final to emphasize the fact that a local declaration is a literal constant and not just an initialized variable. Your mileage may vary.

Frequently you will need more than one class to use the same literal. In fact, if you are doing test-driven development properly, any time you create a literal in code, it is there by virtue of some assertion in a test method against that same literal. A test might say, "assert that these conditions produce an error and that the error message is such-and-such a message." Once this test is written, you then write the production code that produces such-and-such an error message under the right conditions. Now you have code duplication"such-and-such an error message" appears in both the test and the production code.

While a few duplicated strings here and there may seem innocuous, overlooking the need to refactor out this duplication may prove costly in the future. One possibility is related to the growth of your software. Initially you may only deploy your system to local customers. Later, as your software achieves more success, the business may decide that it needs to deploy the software in another country. You will then need to internationalize your software, by deploying it with support for other languages and with consideration for other cultures.

Many software developers have encountered this problem. The software they worked on for months or years has hundreds or thousands of literal Strings strewn throughout the code. It is a major effort to retrofit internationalization support into this software.

As a craftsman of Java code, it is your job to stay vigilant and ensure that duplication is eliminated as soon as you recognize it.[5]

[5] For the problem of duplicated strings, a more robust solution involving resource bundles is more appropriate. See Additional Lesson III for a brief discussion of resource bundles.

Replace common literals with class constants.

A class constant is a field that is declared with the static and final keywords. As a reminder, the final keyword indicates that the field reference cannot be changed to point to a different value. The static keyword means that the field is available for use without having to first construct an instance of the class in which it is declared. It also means that there is one and only one field in memory instead of one field for each object created. The following example declares a class constant:

class ChessBoard { static final int SQUARES_PER_SIDE = 8; }

By convention, class constants appear in uppercase letters. When all letters are uppercase, camel notation is not possible, so the standard is to use underscores to separate words.

You can refer to the class constant by first specifying the class name, followed by the dot (.)operator, followed by the name of the constant.

int numberOfSquares = ChessBoard.SQUARES_PER_SIDE * ChessBoard.SQUARES_PER_SIDE;

You will use class constants already defined in the Java class library in the next section on Dates. Shortly thereafter you will define your own class constant in the CourseSession code.

Категории